Docker 入门 (二)
  pDfpeWmG3ZJk 2023年11月02日 36 0

一、镜像构建

1. 使用 Dockerfile 构建镜像

  Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明

2. Dockerfile 指令详解

FROM

指定基础镜像,所有构建的镜像都必须有一个基础镜像,且 FROM 命令必须是 Dockerfile 的第一个命令。 Dockerfile 存在一个特殊镜像 scratch,表示空白镜像。 FROM <image> [AS <name>] 指定从一个镜像构建起一个新的镜像名字 FROM <image>[:<tag>] [AS <name>] 指定镜像的版本 Tag 示例:FROM mysql:5.0 AS database

RUN

用来执行命令行命令

  • shell 格式 RUN <commond> <shell 命令>
  • exec 格式 RUN ["executable file", "param1", "param2"]

COPY

复制指令,从上下文目录中复制文件或者目录到新一层镜像内的指定路径下。 格式: COPY [--chown=<user>:<group>] <源路径1>... <目标路径> COPY [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"] [--chown=<user>:<group>]:可选参数,用户改变复制到容器内文件的拥有者和属组。 <源路径>:源文件或者源目录,这里可以是通配符表达式,其通配符规则要满足 Go 的 filepath.Match 规则。例如: COPY hom* /mydir/ COPY hom?.txt /mydir/ <目标路径>:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。

ADD

ADD 指令和 COPY 的使用格类似(同样需求下,推荐使用 COPY)。功能也类似,不同之处如下: ADD 的优点:在执行 <源文件> 为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到 <目标路径>。如果源路径是url,Docker 引擎会自动下载至目标路径 ADD 的缺点:在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定。

CMD

指定默认的容器主进程的启动命令,CMD 在 docker run 时 执行 CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。 格式:

  1. CMD <shell 命令>
  2. CMD ["<可执行文件或命令>","<param1>","<param2>",...] CMD ["<param1>","<param2>",...]    #  该写法是为 ENTRYPOINT 指令指定的程序提供默认参数 如果使用 shell 模式,那么实际的命令会被包装成 "sh -c" 的形式执行,有可能发生意想不到的错误,所以推荐使用第二种 exec 模式

ENTRYPOINT

与 CMD 指令一样,当指定了 ENTRYPOINT 指令时,CMD 指令里的命令将会以参数形式传递给 ENTRYPOINT。 如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。 格式: ENTRYPOINT ["<executeable>","<param1>","<param2>",...] 可以搭配 CMD 命令使用:一般是变参才会使用 CMD ,这里的 CMD 等于是在给 ENTRYPOINT 传参 示例: 假设已通过 Dockerfile 构建了 nginx:test 镜像: FROM nginx ENTRYPOINT ["nginx", "-c"] # 定参 CMD ["/etc/nginx/nginx.conf"] # 变参

  1. 不传参运行
$ docker run  nginx:test
# 容器内会默认运行以下命令,启动主进程。
# nginx -c /etc/nginx/nginx.conf
  1. 传参运行
$ docker run  nginx:test -c /etc/nginx/new.conf
# 容器内会默认运行以下命令,启动主进程(/etc/nginx/new.conf:假设容器内已有此文件)
# nginx -c /etc/nginx/new.conf

ENV

设置环境变量,无论是后续的指令还是容器中的程序,都可以使用这里的环境变量。 格式: ENV <key> <value> ENV <key1>=<value1> <key2>=<value2>... 以下示例设置 NODE_VERSION = 7.2.0 , 在后续的指令中可以通过 $NODE_VERSION 引用:

ENV NODE_VERSION 7.2.0
RUN curl -SLO "https://nodejs.org/dist/v\$NODE_VERSION/node-v\$NODE_VERSION-linux-x64.tar.xz" \
  && curl -SLO "https://nodejs.org/dist/v\$NODE_VERSION/SHASUMS256.txt.asc"

ARG

构建参数,与 ENV 作用一致。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。 构建命令 docker build 中可以用 --build-arg <参数名>=<值> 来覆盖。 格式: ARG <参数名>[=<默认值>]

VOLUME

构建镜像时定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。通过 VOLUME 指令创建的挂载点无法指定主机上对应的目录,是自动生成的。容器运行时应尽量保持其内部不发生任何写入操作,数据文件应该保存在数据卷中 作用: 避免重要的数据,因容器重启而丢失,这是非常致命的。 避免容器不断变大。 格式: VOLUME ["<路径1>", "<路径2>"...] VOLUME <路径> 在启动容器 docker run 的时候,我们可以通过 -v 参数修改挂载点。

EXPOSE

暴露容器端口,只是声明容器打算使用什么端口,并不会自动在宿主机进行端口映射。 作用:

  • 帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射。
  • 在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。 格式: EXPOSE <端口1> [<端口2>...]

WORKDIR

指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会自动创建。可通过 docker run 指令中 -w 参数覆盖。 docker build 构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才会一直存在。 格式: WORKDIR <工作目录路径>

USER

用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)。 格式: USER <用户名>[:<用户组>]

HEALTHCHECK

用于指定某个程序或者指令来监控 docker 容器服务的运行状态 格式为:

# 通过在容器中运行命令来检查 器运行状况
HEALTHCHECK [OPTIONS] CMD command 
# 禁用从基本映像继承的任何运行状况检
HEALTHCHECK NONE

参数有3个:

  • 设置在容器启动多长时间后开始检查容器状态: --interval=DURATION (默认为 30s)
  • 设置超时时间,超过这个时间不返回信息表示容器异常:--timeout=DURATION (默认为 30s)
  • 设置重试次数: --retries=N (默认为 3) 如:
HEALTHCHECK --interval=5m --timeout=3s \ 
CMD curl -f http://localhost/ || exit 1

ONBUILD

用于延迟构建命令的执行。简单的说,就是 Dockerfile 里用 ONBUILD 指定的命令,在本次构建镜像的过程中不会执行(假设镜像为 test-build)。当有新的 Dockerfile 使用了之前构建的镜像 FROM test-build ,这时执行新镜像的 Dockerfile 构建时候,会执行 test-build 的 Dockerfile 里的 ONBUILD 指定的命令。 格式: ONBUILD <其它指令>

LABEL

LABEL 指令用来给镜像添加一些元数据(metadata),以键值对的形式,语法格式如下: LABEL <key>=<value> <key>=<value> <key>=<value> ...

3. 创建镜像

在 Dockerfile 文件的存放目录下,执行构建动作。

$ docker build -t nginx:v3 .

. 表示上下文路径,是指 docker 在构建镜像,有时候想要使用到本机的文件(比如复制),docker build 命令得知这个路径后,会将路径下的所有内容打包。

二、常用命令

1. 查看镜像列表

$ docker images

2. 如何获取镜像

从远程仓库拉取

$ docker pull nginx:alpine
$ docker images

使用 tag 命令给镜像打标签

  $ docker tag nginx:alpine 192.168.2.14:5000/nginx:alpine
  $ docker images

本地构建

  $ docker build . -t my-nginx:ubuntu -f Dockerfile

3. 如何通过镜像启动容器

 $ docker run --name my-nginx-alpine -d nginx:alpine

4. 如何知道容器内部运行了什么程序

 # 进入容器内部,分配一个tty终端
 $ docker exec -it my-nginx-alpine /bin/sh
 # ps aux

5. docker怎么知道容器启动后该执行什么命令

通过docker build来模拟构建一个nginx的镜像, 创建Dockerfile

   # 告诉docker使用哪个基础镜像作为模板,后续命令都以这个镜像为基础 
   FROM ubuntu
   # RUN命令会在上面指定的镜像里执行命令 
   RUN apt-get update && apt install -y nginx
   # 告诉docker,启动容器时执行如下命令
   CMD ["/usr/sbin/nginx", "-g","daemon off;"]

构建本地镜像

   $ docker build . -t my-nginx:ubuntu -f Dockerfile

使用新镜像启动容器

    $ docker run --name my-nginx-ubuntu -d my-nginx:ubuntu    

进入容器查看进程

     $ docker exec -it my-nginx-ubuntu /bin/sh
     # ps aux   

6. 如何访问容器内服务

  # 进入容器内部
  $ docker exec -it my-nginx-alpine /bin/sh
  # ps aux|grep nginx
  # curl localhost:80

7. 宿主机中如何访问容器服务

  # 删掉旧服务,重新启动
  $ docker rm -f my-nginx-alpine
  $ docker run --name my-nginx-alpine -d -p 8080:80 nginx:alpine
  $ curl 192.168.2.14:8080

8. docker client 如何与 daemon 通信

 # /var/run/docker.sock
 $ docker run --name portainer -d -p 9001:9000 -v /var/run/docker.sock:/var/run/docker.sock portainer/portainer

9. 查看容器列表

 # 查看运行状态的容器列表
 $ docker ps
 # 查看全部状态的容器列表
 $ docker ps -a

10. 启动容器

   ## 后台启动
   $ docker run --name nginx -d nginx:alpine
   
   ## 映射端口,把容器的端口映射到宿主机中,-p <host_port>:<container_port>
   $ docker run --name nginx -d -p 8080:80 nginx:alpine
   
   ## 资源限制,最大可用内存500M
   $ docker run --memory=500m nginx:alpine

11. 容器数据持久化

   ## 挂载主机目录
   $ docker run --name nginx -d  -v /opt:/opt  nginx:alpine
   $ docker run --name mysql -e MYSQL_ROOT_PASSWORD=123456  -d -v /opt/mysql/:/var/lib/mysql mysql:5.7

12. 进入容器或者执行容器内的命令

   $ docker exec -it <container_id_or_name> /bin/sh
   $ docker exec <container_id_or_name> hostname

13. 主机与容器之间拷贝数据

   ## 主机拷贝到容器
   $ echo '123'>/tmp/test.txt
   $ docker cp /tmp/test.txt nginx:/tmp
   $ docker exec -it nginx cat /tmp/test.txt
   123
   
   ## 容器拷贝到主机
   $ docker cp nginx:/tmp/test.txt ./

14. 挂载已有的数据,重新创建镜像仓库容器

   ## 解压离线镜像文件
   $ tar zxf registry.tar.gz -C /opt
   
   ## 删除当前镜像仓库容器
   $ docker rm -f registry
   ## 使用docker镜像启动镜像仓库服务
   $ docker run -d -p 5000:5000 --restart always -v /opt/registry:/var/lib/registry --name registry registry:2

15. 查看容器日志

   ## 查看全部日志
   $ docker logs nginx
   
   ## 实时查看最新日志
   $ docker logs -f nginx
   
   ## 从最新的100条开始查看
   $ docker logs --tail=100 -f nginx

16. 停止或者删除容器

   ## 停止运行中的容器
   $ docker stop nginx
   
   ## 启动退出容器
   $ docker start nginx
   
   ## 删除非运行中状态的容器
   $ docker rm nginx
   
   ## 删除运行中的容器
   $ docker rm -f nginx

17. 查看容器或者镜像的明细

   ## 查看容器详细信息,包括容器IP地址等
   $ docker inspect nginx
   
   ## 查看镜像的明细信息
   $ docker inspect nginx:alpine

18. 删除镜像

# 导出镜像为文件
$ docker image save centos:v1 -O centos-v1.tar
# 导入镜像
$ docker image load < centos-v1.tar
$ docker image load -i centos-v1.tar
# 删除镜像
$ docker rmi [optinon] image1,image2,...
# 清除本地镜像(慎用)
$ docker image rm $(docker images -qa)

三、容器退出码

1、Exit Code 0

退出代码0表示特定容器没有附加前台进程。 该退出代码是所有其他后续退出代码的例外。 这不一定意味着发生了不好的事情。如果开发人员想要在容器完成其工作后自动停止其容器,则使用此退出代码。 如果你执行 docker run hello-world, 你会得到“Hello from docker!”,但查看容器的时候docker ps -a | grep hello-world,会发现状态码为 0

2、Exit Code 1

程序错误,或者 Dockerfile 中引用不存在的文件,如 entrypoint 中引用了错误的包 程序错误可以很简单,例如 “除以0”,也可以很复杂,比如空引用或者其他程序 crash

3、Exit Code 137

表明容器收到了 SIGKILL 信号,进程被杀掉,对应 kill -9 引发 SIGKILL 的是 Docker Kill。这可以由用户或由 Docker 守护程序来发起,手动执行:docker kill 137 比较常见,如果 pod 中的 limit 资源设置较小,会运行内存不足导致 OOMKilled,此时 state 中的 "OOMKilled" 值为 true,你可以在系统的 dmesg 中看到 oom 日志

4、Exit Code 139

表明容器收到了 SIGSEGV 信号,无效的内存引用,对应 kill -11 一般是代码有问题,或者 docker 的基础镜像有问题

5、Exit Code 143

表明容器收到了 SIGTERM 信号,终端关闭,对应 kill -15 一般对应 docker stop 命令 有时 docker stop 也会导致 Exit Code 137。发生在与代码无法处理 SIGTERM 的情况下,docker 进程等待十秒钟然后发出 SIGKILL 强制退出。

6、不常用的一些 Exit Code

Exit Code 126: 权限问题或命令不可执行 Exit Code 127: Shell 脚本中可能出现错字且字符无法识别的情况 Exit Code 1 或 255:因为很多程序员写异常退出时习惯用 exit(1) 或 exit(-1),-1 会根据转换规则转成 255。这个一般是自定义 code,要看具体逻辑。

7、退出状态码的区间

必须在 0-255 之间,0 表示正常退出 外界将程序中断退出,状态码在 129-255 程序自身异常退出,状态码一般在 1-128 假如写代码指定的退出状态码时不在 0-255 之间,例如: exit(-1),这时会自动做一个转换,最终呈现的状态码还是会在 0-255 之间。我们把状态码记为 code,当指定的退出时状态码为负数,那么转换公式如下:256 – (|code| % 256)

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论