前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >docker 实践手册

docker 实践手册

原创
作者头像
orientlu
修改2020-04-20 12:02:09
8300
修改2020-04-20 12:02:09
举报
文章被收录于专栏:orientluorientlu

toc

准备环境

安装运行

开始前需要了解 docker的一些 基本概念

  • 镜像(Image
  • 容器(Container
  • 仓库(Repository

以 ubuntu 安装 docker 为例:

代码语言:txt
复制
$ sudo apt install docker.io
$ sudo groupadd docker
$ sudo usermod -aG docker $USER   # 否则只能以 root 操作 docker
## 重启终端
$ docker run hello-world

配置环境

代码语言:txt
复制
$ vim  /etc/docker/daemon.json
$ sudo systemctl daemon-reload   # 重载配置
$ sudo systemctl restart docker  # 重启docker server

使用镜像加速器

国内从docker hub拉取镜像困难时,内网其他镜像资源等

代码语言:txt
复制
  {
    "registry-mirrors": [
      "https://registry.docker-cn.com"  # dockerhub 国内
    ]
  }

修改 docker 目录

代码语言:txt
复制
{
    "data-root": "/data/docker",
}
代码语言:txt
复制
sudo rsync -avz /var/lib/docker /data/docker  ## 迁移目录

限制容器 log 大小

避免运行容器log 无限增长

代码语言:txt
复制
"log-driver": "json-file",  
    "log-opts": {  
      "max-size": "10m",   # 10M 
      "max-file": "10"     # 10个
     }

操作命令

基本命令

代码语言:txt
复制
## 拉取镜像,私有镜像需要先登录
$ docker pull [Docker Registry 地址[:端口号]/]仓库名[:标签]
## 运行镜像, -it 交互运行/ -d 后台运行, --rm 容器结束后销毁
$ docker run -it --rm ubuntu:18.04 /bin/bash
## 列出本地镜像
$ docker image ls
## 列出所有容器
$ docker ps -a
$ docker start/stop 容器id/名
## 查看log
$ docker logs -f 容器id #  从启动开始,
# --tail 10 显示历史10,而不是所有.. 详细 help
## 进入后台执行的容器, -i 交互模式, -t 分配终端
$ docker exec -it 容器id /bin/bash

## 导出导入镜像,镜像id
$ docker save 7691a814370e > ubuntu.tar
$ docker load -i ubuntu.tar #导入镜像, 名和tag 同导出

## 导出导入容器,容器id
$ docker export 7691a814370e > ubuntu.tar
$ cat ubuntu.tar | docker import - test/ubuntu:v1.0 #导入为镜像

## 删除容器,镜像
$ docker rm 容器id
$ docker container prune ## 清理所有停止容器
$ docker rmi 镜像id [-f]
$ docker system prune   ### 清理所有无用容器、缓存

容器网络

网络命令参考

网络模式

  • bridge: 默认模式,独立network namespace,通过 docker0 虚拟网桥,主机与容器通信,
  • host: 容器与主机共用 network namespace
  • Containner: 新创建容器和另外一个容器共享同一个 network namespace,两个容器可以通过 lo 直接通信
  • NONE: 容器有自己的network namespace,但是没有配置网卡,ip路由信息,需自己手动配置

网络模式

容器连接外部

容器通过 net 可以直接访问外部网络,主机配置:

代码语言:txt
复制
$sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1

外部连接容器

外部连接容器,需要容器通过 -p(小写指定端口)/-P(大写随机分配端口) 参数指定对外暴露端口,映射到主机上,

代码语言:txt
复制
# docker run -d -p [host]:port:c_port/udp xxxx
$ docker run -d \
    -p 5000:5000 \
    -p 3000:80 \
    training/webapp \
    python app.py

容器互联

容器连接互联,推荐用户自定义网络,不要使用 --links

代码语言:txt
复制
# 新建自定义网络
$ docker network create -d bridge my-net
$ docker run --name cc1 --network my-net ubuntu sh
$ docker run --name cc2 --network my-net ubuntu sh
## 进入 cc1 中,直接执行 ping cc2, 可以ping 通了
## 通过网络,对应容器名在其他容器中会解析为分配的 ip
## 多个容器互联,使用docker-compose,自动分配网络,方便

数据管理

容器与主机外部进行数据交互方式

数据卷

代码语言:txt
复制
## 创建数据卷
$ docker volume create my-vol
$ docker volume ls
## 查看数据卷信息
$ docker volume inspect my-vol
## 启动容器挂载数据卷
$ docker run -d -P \
    --name web \
    --mount source=my-vol,target=/webapp \
    training/webapp \
    python app.py
    
$ $ docker inspect web      # --> "Mounts"下
    
## 删除数据卷
$ docker volume rm my-vol
$ docker volume prune  ## 无主数据卷清理

数据卷 是被设计用来持久化数据的,它的生命周期独立于容器,Docker 不会在容器被删除后自动删除 数据卷,并且也不存在垃圾回收这样的机制来处理没有任何容器引用的 数据卷。如果需要在删除容器的同时移除数据卷,可以在删除容器的时候使用 docker rm -v 这个命令。

数据卷进阶

数据卷容器

容器通过 --volumes-from 挂载到某个容器A创已经建数据卷上,容器A 为数据卷容器。

容器A 不需要处于运行状态,

挂载本机目录

代码语言:txt
复制
## 挂载本机目录(绝对路径,默认读写权限
$ docker run -d -P \
    --name web \
    --mount type=bind,source=/src/webapp,target=/opt/webapp \
    training/webapp \
    python app.py
    
## 设置权限
$ docker run -d -P \
    --name web \
    # -v /src/webapp:/opt/webapp:ro \
    --mount type=bind,source=/src/webapp,target=/opt/webapp,readonly \
    training/webapp \
    python app.py
    
## 直接挂载一个文件
$ docker run --rm -it \
   --mount type=bind,source=$HOME/.bash_history,target=/root/.bash_history \
   ubuntu:18.04 \
   bash

镜像构建

使用 dockerfile

通过 commit 可以构建 image,但是每次 commit 都是叠加了一个层,而且使用 commit 构建 image,后期不确定 image 中包含了什么操作。

使用 dockerfile 描述构建的 image,每一个 RUN 实际也会对应叠加一层,所以构建时,把多个命令放在同一个 RUN, 减少无意义中间层(image 包含层数是有限制的),还要注意构建命令结尾记得清理无用的文件,避免构造的 image 臃肿。

镜像构建上下文

构建镜像时使用如下命令,

$ docker build -t xx/xx .

docker build 中这个 . 是指定构建镜像的上下文路径(不要理解为当前路径),由于docker运行时是使用 c/s 模式,当在命令行执行 docker build,实际是执行远程调用,通知 docker 引擎完成实际任务,请求时会把上下文路径下的文件打包发给服务端(docker引擎)。

比如构建镜像中时常有 ADD, COPY, 这些命令将指定文件拷贝到镜像中,并不是拷贝执行 docker build 当前目录下的文件,而是从打包过去的文件寻找。

所以,如果这样写

ADD ../file.xx /root/

是无法工作的,因为已经超出了上下文,请求是并没有打包给引擎,自然无法找到。

基于上下文这个概念,构建镜像时,应该保持指定路径下只包含需要的文件,避免打包无关文件(或添加 .dockerignore 文件),这也是通常新建个目录的原因

至于指定 dockerfile,使用参数 -f

代码语言:txt
复制
$  docker build -t nginx:v3 .

docker build 可以直接指定 git rep 构建、tar包构建,等;

一般来说,使用 Dockerfile 构建镜像时最好是将 Dockerfile 放置在一个新建的空目录下。然后将构建镜像所需要的文件添加到该目录中。为了提高构建镜像的效率,可以在目录下新建一个 .dockerignore 文件来指定要忽略的文件和目录。.dockerignore 文件的排除模式语法和 Git 的 .gitignore 文件相似。

构建脚本的命令

dockerfile 每执行一条指令就会建立一层,所以将多个命令合并,减少层数过多,

From 指定基础镜像

设置工作路径

workdir xxx

设置当前工作路径(以后各层也一样),目录不存在会自动创建

dockerfile 不同于shell,前后两行是不同执行环境,所以之后无法在 app 下找到 install.sh

代码语言:txt
复制
RUN cd /app
RUN copy install.sh .

Run 运行命令

  • shell 格式: RUN echo "xx" > xx.md
  • exec 格式:RUN "echo", "xx",">","xx.md" shell 格式实际执行会包装为 "sh","-C", "xx",环境变量什么能被shell解析
代码语言:txt
复制
RUN ["echo", "$HOME"]  # 没有shell解析,打印 "$HOME"
RUN echo $HOME   # shell解析,打印出路径

exec 要使用""括起来,因为会被解析为json

合并多条命令,避免镜像建立太多层,

代码语言:txt
复制
FROM debian:stretch

RUN buildDeps='gcc libc6-dev make wget' \
    && apt-get update \
    && apt-get install -y $buildDeps \
    && wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \
    && mkdir -p /usr/src/redis \
    && tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \
    && make -C /usr/src/redis \
    && make -C /usr/src/redis install \
    && rm -rf /var/lib/apt/lists/* \
    && rm redis.tar.gz \
    && rm -r /usr/src/redis \
    && apt-get purge -y --auto-remove $buildDeps  ## 清理安装内容

copy 和 add 的差别

copy 将上下文目录中的文件、目录复制到新一层镜像内,

代码语言:txt
复制
COPY package.json /usr/src/app/
COPY hom* /mydir/
COPY hom?.txt /mydir/

<目标路径> 可以是容器内的绝对路径,也可以是相对于 WORKDIR 指令设置的工作路径,不需要事先创建,如果目录不存在会在复制文件前先行创建缺失目录。使用 COPY 指令,源文件的各种元数据都会保留。比如读、写、执行权限、文件变更时间等。

在使用该指令的时候还可以加上 --chown=<user>:<group> 选项来改变文件的所属用户及所属组。

COPY --chown=66:mygroup files* /mydir/

add 和 copy 一样,但是在其基础加了其他功能:

  • add 的原路径可以是 URL,构建时会自动拉取,设置权限为 600,如果是压缩不会自动解压
  • add 如果是个压缩包,会自动解压

另外,add 可能导致构建缓存失效,所以:

大部分情况使用 copy,语义明确,需要解压缩再使用add 就好;

entrypoint 和 cmd 差别

entrypoint 和cmd 都和run一样,支持 shell 和exec格式,

docker 不是虚拟机,容器中的应用应该以前台执行(容器中没有后台运行的服务),启动时需要给出运行的bin和参数,通过 entrypoint 和 cmd 命令来实现,一般推荐用exec格式,shell 格式容易混淆前后台执行。

例子:

代码语言:txt
复制
cmd ["echo","echo_cmd"]
entrypoint ["echo", "echo_entry"]
代码语言:txt
复制
# 以上cmd和entrypoint都设置,运行时不带参数,实际运行命令:
echo echo_entry echo echo_cmd   ## $entrypoint $cmd
# 以上cmd和entrypoint都设置,运行时带参数 hello,实际运行命令:
echo echo_entry hello           ## $entrypoint hello, cmd 被覆盖

# entrypoint设置,运行时不带参数,实际运行命令:
echo echo_entry               ## $entrypoint
# entrypoint设置,运行时带参数 hello,实际运行命令:
echo echo_entry hello  ## $entrypoint hello

# cmd设置,运行时不带参数,实际运行命令:
echo echo_cmd               ## $cmd
# cmd 设置,运行时带参数 hello,实际运行命令:
hello (报错,除非hello是可执行的)
# cmd 设置,运行时带参数 echo xxx,实际运行命令:
echo xxx
  • 在运行镜像时,如果跟着其他参数,cmd就会被覆盖,而如果想覆盖 entrypoint 需要指定 --entrypoint
  • 如果有 entrypoint,cmd 会作为默认参数传递给 entrypoint 作为执行参数;运行时传入参数,cmd 就会被覆盖,入口依然是entrypoint
  • 如果没有 entrypoint,cmd 直接作为默认执行入口+参数;运行时执行入口+参数可以被传入替换

用 entrypoint 指定入口,用 cmd 指定默认参数,使镜像可以想工具一样使用,以及确保镜像启动一定做好准备工作(比如设置entryppoint 固定为初始化脚本,根据cmd传入去指定之后的事)

参考:

https://zhuanlan.zhihu.com/p/30555962

https://yeasy.gitbooks.io/docker_practice/image/dockerfile/entrypoint.html

设置环境变量

代码语言:txt
复制
ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...

传递参数

代码语言:txt
复制
ARG MY_ENV="default/xxx"  ## dockerfile 声明参数
ENV $MY_ENV             ## 引用参数

构建时传入:

--build-arg MY_ENV="XXX"

健康检查

代码语言:txt
复制
FROM nginx
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
HEALTHCHECK --interval=5s --timeout=3s \
  CMD curl -fs http://localhost/ || exit 1

忽略错误

代码语言:txt
复制
RUN make; exit 0

onbuild 命令

指定当前镜像不运行,在当前镜像作为基础镜像构建其他镜像才运行的命令;

https://yeasy.gitbooks.io/docker_practice/image/dockerfile/onbuild.html

构建缓存问题

Docker构建是分层的,一条指令一层,在docker build 没有带--no-cache=true 指令的情况下如果某一层没有改动,Docker就不会重新构建这一层而是会使用缓存。

通过适当的拆分指令,达到分层利用缓存,提高构建速度。

代码语言:txt
复制
copy go.mod .
RUN go mod download   # 先拷贝go.mod下载,
                                  # 后面如果依赖不变,则不需要重复download
copy . .
RUN make

但是有些时候也要避免cache带来问题,如不要把 update 和 install 拆分,不然后面新增应用,但是update只会第一次执行。

代码语言:txt
复制
RUN apt-get update && apt-get install -y \
    aufs-tools \
    automake \
    build-essential \
    curl \
    dpkg-sig \
    libcap-dev \
    libsqlite3-dev \
    mercurial \
    reprepro \
    ruby1.9.1 \
    ruby1.9.1-dev \
    s3cmd=1.1.* \
 && rm -rf /var/lib/apt/lists/*

分阶段构建

在同一个镜像中完成应用构建和执行,可能导致镜像臃肿,代码泄露等问题,因此需要多阶段构建;

构建阶段,构建镜像中完成应用构建;之后将构建产物拷贝到运行镜像(运行镜像只包含运行需要的依赖,小巧)

代码语言:txt
复制
FROM golang:1.9-alpine as builder
RUN apk --no-cache add git
WORKDIR /go/src/github.com/go/helloworld/
RUN go get -d -v github.com/go-sql-driver/mysql
COPY app.go .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .


FROM alpine:latest as prod
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=0 /go/src/github.com/go/helloworld/app .
CMD ["./app"]

远程仓库

代码语言:txt
复制
$ sudo docker login --username=xx url
$ docker  pull hub/image:xxx
$ docker push hub/image:xxx

docker-compose

代码语言:txt
复制
version: "3"

services:
  loraserver:
    image: ccr.ccs.tencentyun.com/lora/networkserver:${run_ver}
    volumes:
      - ${work_path}/configuration/loraserver:/etc/loraserver
      - /etc/localtime:/etc/localtime:ro
    environment:
      - JOIN_SERVER.DEFAULT.SERVER=http://appserver:8003
      
  appserver:
    image: ccr.ccs.tencentyun.com/lora/appserver:${run_ver}
    logging:
      driver: "json-file"
      options:
        max-size: "200m"
        max-file: "10"
    ports:
      - ${as_api_port}:8080
    volumes:
      - asdata:/lora-app-server
      - /etc/localtime:/etc/localtime:ro
    depends_on:
      - loraserver
  
  volumes:
    asdata:

参考

命令

参考

数据

数据卷 或者 直接挂载本地目录

网络

参考

参考

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 准备环境
    • 安装运行
      • 配置环境
        • 使用镜像加速器
        • 修改 docker 目录
        • 限制容器 log 大小
    • 操作命令
      • 基本命令
        • 容器网络
          • 网络模式
          • 容器连接外部
          • 外部连接容器
          • 容器互联
        • 数据管理
          • 数据卷
          • 挂载本机目录
      • 镜像构建
        • 使用 dockerfile
          • 镜像构建上下文
            • 构建脚本的命令
              • From 指定基础镜像
              • 设置工作路径
              • Run 运行命令
              • copy 和 add 的差别
              • entrypoint 和 cmd 差别
              • 设置环境变量
              • 传递参数
              • 健康检查
              • 忽略错误
              • onbuild 命令
            • 构建缓存问题
              • 分阶段构建
                • 远程仓库
                • docker-compose
                  • 命令
                    • 数据
                      • 网络
                      • 参考
                      相关产品与服务
                      容器服务
                      腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档