Yin的笔记本

vuePress-theme-reco Howard Yin    2021 - 2025
Yin的笔记本 Yin的笔记本

Choose mode

  • dark
  • auto
  • light
Home
Category
  • CNCF
  • Docker
  • namespaces
  • Kubernetes
  • Kubernetes对象
  • Linux
  • MyIdeas
  • Revolution
  • WebRTC
  • 云计算
  • 人工智能
  • 分布式
  • 图像处理
  • 图形学
  • 微服务
  • 数学
  • OJ笔记
  • 博弈论
  • 形式语言与自动机
  • 数据库
  • 服务器运维
  • 编程语言
  • C
  • Git
  • Go
  • Java
  • JavaScript
  • Python
  • Nvidia
  • Shell
  • Tex
  • Rust
  • Vue
  • 视频编解码
  • 计算机网络
  • SDN
  • 论文笔记
  • 讨论
  • 边缘计算
  • 量子信息技术
Tag
TimeLine
About
查看源码
author-avatar

Howard Yin

304

Article

153

Tag

Home
Category
  • CNCF
  • Docker
  • namespaces
  • Kubernetes
  • Kubernetes对象
  • Linux
  • MyIdeas
  • Revolution
  • WebRTC
  • 云计算
  • 人工智能
  • 分布式
  • 图像处理
  • 图形学
  • 微服务
  • 数学
  • OJ笔记
  • 博弈论
  • 形式语言与自动机
  • 数据库
  • 服务器运维
  • 编程语言
  • C
  • Git
  • Go
  • Java
  • JavaScript
  • Python
  • Nvidia
  • Shell
  • Tex
  • Rust
  • Vue
  • 视频编解码
  • 计算机网络
  • SDN
  • 论文笔记
  • 讨论
  • 边缘计算
  • 量子信息技术
Tag
TimeLine
About
查看源码
  • Dockerfile的一些补充知识

    • 向进程发送停止信号
      • 多阶段构建 - multi-stage builds
        • 示例
        • 使用多阶段构建
      • 奇怪的错误
        • Dockerfile的CMD和Shell脚本
          • 在Dockerfile的CMD里写变量
            • docker build的网络连接

            Dockerfile的一些补充知识

            vuePress-theme-reco Howard Yin    2021 - 2025

            Dockerfile的一些补充知识


            Howard Yin 2019-12-03 16:04:03 DockerDockerfile实操

            # 向进程发送停止信号

            默认情况下,docker容器在停止时会向容器内的1号进程发送SIGTERM信号告知应用停止。

            在命令行运行docker容器时,在容器stdout输出界面(docker run不加-d)中Ctrl+C就是向1号进程发送SIGTERM信号,然后退出容器的stdout(离开容器的stdout回主机命令行),此时容器可能没有完全退出,继续在后台运行,用docker ps可以看到,这种容器就要调用docker stop才能完全停止。docker stop是不管容器内的进程状态如何都直接强行退出。

            用docker-compose运行容器时,在stdout输出界面按Ctrl+C或者用docker-compose down就是向1号进程发送SIGTERM信号,这时docker-compose会等待容器自己退出,并且下面会显示“按Ctrl+C强制退出”之类的话,这时再按Ctrl+C就是和docker stop一样的效果。

            SIGTERM信号相当于是kill <PID>指令,但是有些程序被设置成要接收SIGINT信号才退出(SIGINT信号就相当于在命令行Ctrl-C)。这时就要在Dockerfile里面设置容器的停止指令:

            STOPSIGNAL SIGINT
            
            1

            这样,容器退出时向1号进程发送的信号就不是SIGTERM而是SIGINT了。

            # 多阶段构建 - multi-stage builds

            在从源码开始的镜像构建时经常遇到一种情况:源码的编译需要一个超大的编译用镜像,而编译完成之后就只需要一个基础的操作系统镜像就能运行。以最典型的go语言为例,编译时需要用golang镜像,并且还要下一堆go库,但是编译完成之后就只用把可执行文件拿到一个啥软件都没有的基础镜像里面就能运行。

            在多阶段构建出现之前,像golang和C这类静态编程语言用在Docker里面至少需要两个镜像,一个用来构建,一个用来运行,构建用的镜像通常很大,运行用的镜像就很小。这种搞法就至少要写两个Dockerfile,很不方便,不够简洁。

            多阶段构建就是解决这个问题存在的。

            多阶段构建使用一个文件同时编译多个镜像,不同的镜像进行不同的操作,最后汇总到一个镜像中。其用法非常简单:

            • 把编译镜像和运行镜像的Dockerfile合并写入一个文件中,最终要生成的运行镜像放在最下面
            • 把运行镜像Dockerfile里面原有的复制可执行文件的指令加上--from参数,使之从编译镜像中复制文件

            # 示例

            # 不使用多阶段构建

            构建用镜像:

            FROM golang:alpine
            WORKDIR /go/src
            RUN apk --update add git && \
                go get -d -v github.com/kataras/iris && \
                go get -d -v github.com/go-sql-driver/mysql && \
                go get -d -v github.com/gocql/gocql && \
                go get -d -v github.com/garyburd/redigo/redis && \
                go get -d -v gopkg.in/yaml.v3
            RUN mkdir /app
            WORKDIR /app
            VOLUME  ["/app"]
            
            1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11

            构建指令:

            docker run -it --rm -v "$(pwd):/app" yindaheng98/go-iris go build -v -o /app/UserAuth
            
            1

            运行用镜像:

            FROM alpine
            RUN mkdir /Config
            ADD UserAuth /
            RUN chmod u+x /UserAuth
            ADD Config /Config
            EXPOSE 8080
            WORKDIR /
            VOLUME [ "/Config" ]
            ENTRYPOINT ["/UserAuth" ]
            
            1
            2
            3
            4
            5
            6
            7
            8
            9

            # 使用多阶段构建

            FROM golang:alpine AS builder
            WORKDIR /go/src
            RUN apk --update add git && \
                go get -d -v github.com/kataras/iris && \
                go get -d -v github.com/go-sql-driver/mysql && \
                go get -d -v github.com/gocql/gocql && \
                go get -d -v github.com/garyburd/redigo/redis && \
                go get -d -v gopkg.in/yaml.v3
            ADD ./ /app
            WORKDIR /app
            RUN go build -v -o /UserAuth
            
            FROM alpine
            RUN mkdir /Config
            COPY --from=builder /UserAuth /
            RUN chmod u+x /UserAuth
            ADD Config /Config
            EXPOSE 8080
            WORKDIR /
            VOLUME [ "/Config" ]
            ENTRYPOINT ["/UserAuth" ]
            
            1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            15
            16
            17
            18
            19
            20
            21

            # 奇怪的错误

            当前文件夹下存在etc、/etc/glusterfs、etc-etc、etc-etc/etc

            下面这个指令没有问题👇

            docker run --rm -v "./etc:/etc/glusterfs" gluster/gluster-centos
            docker run --rm -v "./etc/glusterfs:/etc/glusterfs" gluster/gluster-centos
            
            1
            2

            下面这个就有问题👇

            docker run --rm -v "./etc/glusterfs:/etc/glusterfs" gluster/gluster-centos
            docker run --rm -v "./etc-etc:/etc/glusterfs" gluster/gluster-centos
            
            1
            2

            报这种错👇

            C:\Program Files\Docker\Docker\Resources\bin\docker.exe: Error response from daemon: create etc/glusterfs: "etc/glusterfs" includes invalid characters for a local volume name, only "[a-zA-Z0-9][a-zA-Z0-9_.-]" are allowed. If you intended to pass a host directory, use absolute path.
            See 'C:\Program Files\Docker\Docker\Resources\bin\docker.exe run --help'.
            
            1
            2

            这么说Docker只能挂载一层相对目录???在docker-compose.yml里面就没这问题。

            # Dockerfile的CMD和Shell脚本

            1. Shell脚本开头最好加#! /bin/bash以免报错
            2. 下面这两个CMD效果是不一样的👇
            CMD [ "sh", "-c", "start.sh" ]
            
            1

            这个正常👆

            CMD [ "start.sh" ]
            
            1

            这个会让容器启动时直接exit 0。原因?不太懂。

            # 在Dockerfile的CMD里写变量

            这样写CMD的结果是什么?👇

            FROM alpine
            ENV SOME_PATH /some/path
            CMD [ "echo", "${SOME_PATH}" ]
            
            1
            2
            3

            会echo出SOME_PATH的值吗?

            答案是不会。会echo出"${SOME_PATH}"这个字符串。

            那能把SOME_PATH和echo写在一起吗?👇

            FROM alpine
            ENV SOME_PATH /some/path
            CMD [ "echo", "${SOME_PATH}" ]
            
            1
            2
            3

            也不行。会报错:exec: \"echo ${SOME_PATH}\": executable file not found in $PATH,这就是说docker不知道怎么地把echo ${SOME_PATH}搞成一整个指令了。

            那不加引号呢?👇

            FROM alpine
            ENV SOME_PATH /some/path
            CMD [ echo, ${SOME_PATH} ]
            
            1
            2
            3

            也不行,还是报错:sh: /some/path: unknown operand。终于算是识别出${SOME_PATH}的值了,可是又不知怎的变成指令了???

            那么,正确方法是什么?请看👇

            FROM alpine
            ENV SOME_PATH /some/path
            CMD echo ${SOME_PATH}
            
            1
            2
            3

            # docker build的网络连接

            docker build镜像时,默认使用网桥(bridge)模式,容器时虚拟环境,没有自己的网卡,所以无法连接网络。

            好在docker在构建(build)或者运行(run)镜像时都提供了选择网络的参数,我们可以使用宿主机的网络,方式是--network host指令。

            docker build -t archieves_center . --network host
            
            1

            可是在win上就不用这样?奇怪了。

            帮助我们改善此页面!
            创建于: 2019-10-18 07:18:05

            更新于: 2019-12-03 16:04:32