Docker

Docker Compose 教程

使用 docker run 运行容器的时候经常需要加很多的参数,每次都输入这么多参数很容易出错。另外我们经常需要同时运行若干个容器来构成一个服务,此时还是涉及到网络的联通等操作。docker compose 可以把 docker 执行时的参数写成 yaml 文件,运行的时候只需要 docker-compose up -d 一下就可以了。

话不多说,下面通过一个例子来学习一下 docker-compose.yml 文件的语法。

version: "3"  # 版本号,目前最新版是 3,不同版本的语法是不太兼容的
services:  # 定义的服务,注意是一个字典
  web:
    build: .
    environment:  # 定义环境变量
      - ENV=prod
    depends_on:  # 该服务依赖下面的两个服务,也就是指定了
      - db
      - redis
  redis:
    image: redis  # 使用 dockerhub 上的 redis 镜像,这里也可以填自己的私有地址
    ports:
     - "3000"
     - "3000-3005"
     - "8000:8000"
     - "9090-9091:8080-8081"
     - "49100:22"
     - "127.0.0.1:8001:8001"
     - "127.0.0.1:5000-5010:5000-5010"
     - "6060:6060/udp"
  db:
    image: postgres
    volumes:
      - "/var/run/postgres/postgres.sock:/var/run/postgres/postgres.sock"
      - "dbdata:/var/lib/postgresql/data"  # 挂载的库,为了和 yaml 语法兼容,必须用引号

volumes:  # 定义的卷
  - dbdata
  1. version 指定了当前 docker-compose 文件的版本
  2. services 服务列表,是一个 "服务名:配置" 的字典。这里定义了三个服务:
    web/redis/db
  3. build,docker build 命令的参数,用来指定需要构建的 dockerfile
  4. image,如果镜像不需要自己构建,而是使用dockerhub上的基础镜像,可以直接使用
    image 指令
  5. depends_on 指定当前的服务依赖的服务,从而确定启动顺序
  6. ports 开放的端口的数组,有三种形式:
    1. "3000" 容器中开放的端口
    2. "3000:3000" 开放容器中的端口到宿主机
    3. "127.0.0.1:3000:3000" 开放容器中的端口到宿主机并绑定IP
  7. environment 环境变量
  8. volumes 挂载的卷,可以使用named volume或者是挂载目录,建议不要使用匿名卷。如
    果使用 named volume,必须在volumes下声明

运行服务

docker-compose 有以下3个常用命令:

  1. docker-compose up [-d] [SERVICE] 启动服务,-d 表示以 daemon 形式后台运行,并且会在重启后自动启动。
  2. docker-compose run
  3. docker-compose stop

Dockerfile 基础教程

Dockerfile 列出了构建一个docker image 的可复现步骤。比起一步一步通过 docker commit 来制作一个镜像,dockerfile更适用于 CI 自动测试等系统。

Dockerfile 命令

  • FROM,指定基础镜像
  • MAINTAINER,作者,建议格式(Jon Snow <jonsnow@westros.com>
  • EXPOSE,需要暴露的端口,但是一般也会使用 -p 来制定端口映射
  • USER,运行的用户
  • WORKDIR,进程的工作目录
  • COPY,复制文件到
  • RUN,运行shell命令
  • CMD,启动进程使用的命令
  • ENTRYPOINT,镜像启动的入口,默认是 bash -c
  • ENV,设定环境变量
  • VOLUME,卷

几个比较容易混淆的

COPY vs ADD

ADD 会自动解压压缩包,在不需要特殊操作的时候,最好使用COPY。

ENTRYPOINT vs CMD

entrypoint 指定了 Docker 镜像要运行的二进制文件(当然也包括参数),而 cmd 则指定了运行这个二进制文件的参数。不过因为默认 entrypoint 是 bash -c,所以实际上 CMD 指定的也是要运行的命令。

另外,docker run 时候包含命令行参数,会执行命令行参数,而不是 CMD 的内容。如果使用 /bin/bash 作为命令行的指令,这样便替换掉 CMD 的内容,从而进入镜像中查看编译出的镜像究竟是什么样的。

个人倾向于只使用 CMD,而不使用 ENTRYPOINT

如何理解 VOLUME 指令

Dockerfile 中的 volume 指定了一个匿名的 docker volume,也就是说在 docker run 的时候,docker 会把对应的目录mount 到一个匿名的卷。当然如果使用 -v 参数指定了 mount 到哪个目录,或者是指定了卷名,那就不会采用匿名的卷了。

使用Dockerfile 还是 commit 来构建镜像

如果可能的话,尽量使用 dockerfile,因为是可复现的。

I’ve been wondering the same thing, and my impression (which could be totally wrong) it that it’s really the same case as with VMs –> you don’t want to not know how to recreate the vm image. In my case I have regular .sh scripts to install, and am wondering why I can’t just maintain these, run docker and effectively call these, and create the golden version image that way. My scripts work to get it installed on a local PC, and the reason I want to use docker is to deal with conflicts of multiple instances of programs/have clean file system/etc
https://stackoverflow.com/questions/26110828/should-i-use-dockerfiles-or-image-commits

参考

  1. https://stackoverflow.com/a/34245657/1061155
  2. https://stackoverflow.com/questions/41935435/understanding-volume-instruction-in-dockerfile