跳到主要内容

Docker-compose安装和使用

安装

  1. Linux安装Docker
yum -y install docker-io
  1. 启动Docker
service docker start

# 加入开机启动
chkconfig docker on
  1. 安装docker-compose
pip install -U docker-compose

Dockerfile文件说明

基础命令

  1. FROM:指定基础镜像

    比如:FROM tomcat<:tags>

    第一条指令必须为FROM指令,并且,如果在同一个Dockerfile中创建多个镜像时,可以使用多个FROM指令【每个镜像一次】

  2. LABEL&MAINTAINER:指定维护着的信息

    • MAINTAINER: 一般写个人id或者组织id
    • LABEL:就是注释,方便阅读,纯注释说明
    MAINTAINER zhangsan
    LABEL version = "1.0.0"
    LABEL description = "我是李四"
  3. WORKDIR 类似linuxcd命令,不过会判断有没有这个目录,没有就会自动创建,然后cd进去

  4. COPY:将文件从 本地 复制到 镜像

    • COPY 1.txt /,将1.txt复制到根目录下

    • 拷贝所有 abc 开头的文件到testdir目录下 COPY abc* /testdir/

    • ? 是单个字符的占位符,比如匹配文件 abc1.log COPY abc?.log /testdir/

  5. ADD :将文件从 本地 复制到镜像。可以是Dockerfile所在的目录的一个相对路径;可以是URL,也可以是tar.gz(自动解压)

示例:

  • 将1.txt拷贝到根目录的abc目录下。若/abc不存在,则会自动创建 ADD 1.txt /abc

  • 将test.tar.gz解压缩然后将解压缩的内容拷贝到/home/work/test ADD test.tar.gz /home/work/test

提示

docker官方建议当要从远程复制文件时,尽量用curl/wget命令来代替ADD。因为用ADD的时候会创建更多的镜像层。镜像层的size也大。

  1. COPYADD比较

    • COPY能干的事ADD都能干,甚至还有附加功能。
    • ADD可以支持拷贝的时候顺带解压缩文件,以及添加远程文件(不在本宿主机上的文件)类似wget。
    • 只是文件拷贝的话可以用COPY,有额外操作只能用ADD代替。
  2. ENV:设置环境变量,环境变量可以被后面的指令使用,例如:

    • 设置环境常量,方便下文引用,比如: ENV JAVA_HOME /usr/local/jdk1.8
    • 引用上面的常量,下面的RUN指令可以先不管啥意思,目的是想说明下文可以通过${xxx}的方式引用 RUN ${JAVA_HOME}/bin/java -jar xxx.jar
  3. VOLUME:创建一个可以从本地主机或其他容器挂载的挂载点,一般用来存放数据库和需要保持的数据等。

运行指令

  • RUN
  • CMD
  • ENTRYPOINT

RUN:构建镜像时执行的命令。

  1. 执行时机

    RUN指令是在构建镜像时运行,在构建时能修改镜像内部的文件。每条指令将在当前镜像基础上执行,并提交为新的镜像。

  2. 命令格式

注: 命令格式不光是RUN独有,而是下面的CMD和ENTRYPOINT都通用。

SHELL命令格式

RUN yum -y install vim

EXEC命令格式

RUN [“yum”,"-y",“install”,“vim”]

二者对比

  • SHELL:当前shell是父进程,生成一个子shell进程去执行脚本,脚本执行完后退出子shell进程,回到当前父shell进程。

  • EXEC:用EXEC进程替换当前进程,并且保持PID不变,执行完毕后直接退出,不会退回原来的进程。

总结

也就是说shell会创建子进程执行,EXEC不会创建子进程。

  1. 举例

举个最简单的例子,构建镜像时输出一句话,那么在Dockerfile里写如下即可:

RUN [“echo”, “image is building!!!”]

再比如我们要下载vim,那么在Dockerfile里写如下即可:

RUN [“yum”,"-y",“install”,“vim”]

CMD

  1. 执行时机:容器启动时执行,而不是镜像构建时执行。

  2. 解释说明:容器启动时运行指定的命令。

Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效。重点在于如果容器启动的时候有其他额外的附加指令,则CMD指令不生效。

  1. 举例:

    CMD [“echo”, “container starting…”]

ENTRYPOINT

  1. 执行时机:容器创建时执行,而不是镜像构建时执行。

  2. 解释说明:在容器启动的时候执行此命令,且Dockerfile中只有最后一个ENTRYPOINT会被执行,推荐用EXEC格式。

  3. 举例

    ENTRYPOINT [“ps”,"-ef"]

RUN vs CMD vs ENTRYPOINT

简单的说:

  1. RUN 执行命令并创建新的镜像层,RUN 经常用于安装软件包。
  2. CMD 设置容器启动后默认执行的命令及其参数,但 CMD 能够被 docker run 后面跟的命令行参数替换。
  3. ENTRYPOINT 配置容器启动时运行的命令。

RUN

RUN是在构建层面的,就是每执行一个RUN,就代表多一层。所以我们经常会用于安装软件包,好比 RUN yum -y install vim。执行这个命令就是让当前镜像可以支持vim指令。


CMD

CMD 指令允许用户指定容器的默认执行的命令。此命令会在容器启动且 docker run 没有指定其他命令时运行。如果 docker run 指定了其他命令,CMD 命令将被忽略。

如果 Dockerfile 中有多个 CMD 指令,只有最后一个 CMD 有效。


ENTRYPOINT

ENTRYPOINT 指令可让容器以应用程序或者服务的形式运行。ENTRYPOINT 看上去与 CMD 很像,它们都可以指定要执行的命令及其参数。不同的地方在于 ENTRYPOINT

不会被忽略,一定会被执行,即使运行 docker run 时指定了其他命令。

RUN VS CMD案例

上面虽然用文字阐述了它们之间的区别,但是估计还是会有点不太明白,所以这里通过一个小小案例来理解。

创建Dockerfile,并添加如下内容

FROM centos
RUN [“echo”, “image building!!!”]
CMD [“echo”, “container starting…”]

构建镜像

docker build -t runvscmd-test .

可以看出构建镜像的过程中发现RUN的image building!!! 输出了,所以RUN命令是在镜像构建时执行。而并没有container starting…的输出。

启动容器

docker run runvscmd-test

启动容器的时候 container starting…,足以发现CMD命令是在容器启动的时候执行。

总结: 这就是上面所说的 run是 构建镜像 时候的指令,CMD和ENTRYPOINT是启动容器时的指令。

CMD VS ENTRYPOINT案例

ENTRYPOINT和CMD可以共用,若共用则他会一起合并执行。如下Demo:

FROM centos
RUN [“echo”, “image building!!!”]
ENTRYPOINT [“ps”]
CMD ["-ef"]

构建启动容器

构建镜像

docker build -t docker-test .

启动容器

docker run docker-test

输出结果

UID PID PPID C STIME TTY TIME CMD
root 1 0 0 13:02 ? 00:00:00 ps -ef

他给我们合并执行了:ps -ef,这么做的好处在于如果容器启动的时候添加额外指令,CMD会失效,可以理解成我们可以动态的改变CMD内容而不需要重新构建镜像等操作。比如

docker run docker-test -aux

输出结果:

USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 2.0 0.0 46340 1692 ? Rs 13:02 0:00 ps -aux

结果直接变成了 ps -aux,CMD命令不执行了。

总结:从这个示例中就可以看出区别,ENTRYPOINT无论容器启动是否带参数,都会执行。而CMD就不一样。上面没带参数那么它就会被执行。而下面带了 -aux,

CMD指令就不会执行了。

使用

├── base
│   ├── Dockerfile
│   ├── Makefile
│   ├── README.md
│   ├── base // base 可执行文件
│   ├── domain
│   │   ├── model
│   │   ├── repository
│   │   └── service
│   ├── filebeat.yml
│   ├── go.mod
│   ├── go.sum
│   ├── handler
│   │   └── baseHandler.go
│   ├── main.go
│   ├── plugin
│   │   └── hystrix
│   └── proto
│   └── base
└── docker-compose
└── chapter2
└── docker-compose.yml

目录示意如上:

version: '3'
services:
# base 服务
base-service:
build:
context: ../../base # 上上层目录中的 base 目录
dockerfile: Dockerfile # 上上层目录中的base目录下的 Dockerfile
# 构建生成的镜像文件
# build 的时候会生成
# up 会去查找并启动
image: base-service:2.0.0
# 指定容器的名称 小写
container_name: base-wj-service
# 重启策略
restart: always
# 端口 注意是否已经被占用
ports:
- "5000:5000"
- "8080:8080"
chapter2 sudo docker-compose build base-service                
[+] Building 0.3s (8/8) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 31B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/alpine:latest 0.2s
=> [1/3] FROM docker.io/library/alpine@sha256:21a3deaa0d32a8057914f36584b5288d2e5ecc984380bc0118285c70fa8c9300 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 60B 0.0s
=> CACHED [2/3] ADD base /base 0.0s
=> CACHED [3/3] ADD filebeat.yml /filebeat.yml 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:01debd0cce93d76fb37d642fb72bfce03dca7c435f9fc4be4410044704b61581 0.0s
=> => naming to docker.io/library/base-service:2.0.0

我们可以使用docker images | grep base来查看是否有这个镜像生成

我们还可以使用docker-compose up来启动容器

chapter2 docker-compose up -d                            
[+] Running 1/1
⠿ Container base-wj-service Started 0.4s
➜ chapter2 docker ps | grep base
1016f3e39582 base-service:2.0.0 "/base" 6 seconds ago Up 5 seconds 0.0.0.0:5001->5001/tcp, 0.0.0.0:8080->8080/tcp base-wj-service

可以使用docker-compose down来关闭并删除容器以及对应的网络设置

chapter2 sudo docker-compose down              
[+] Running 2/2
⠿ Container base-wj-service Removed 0.0s
⠿ Network chapter2_default Removed