使用Dockerfile构建容器Dockfile 是一种被 Docker 程序解释的脚本,Dockerfile 由一条一条的指令组成,每条指令对  Linux Docker  Dockerfile 正的 Linux Dockerfile 有自己书写格式和支持的命令,Docker 程序解决这些命令间的依赖关系,类似于 MakefileDocker 读取 Dockerfile制的 image相比 image Dockerfile 这种显而易见的脚本更容易被使用者接受,它明确的表明 p_w_picpath 是怎么产生的。有了 Dockerfile,当我们需要定制自己额外的需求时,只需在 Dockerfile 上添加或者修改指令,重 新生成 p_w_picpath 即可,省去了敲命令的麻烦。

Dockerfile 由一行行命令语句组成,并且支持以#开头的注释行。

Dockerfile 的指令是忽略大小写的,建议使用大写,每一行只支持一条指令,每条指令可以 携带多个参数。

Dockerfile 的指令根据作用可以分为两种,构建指令和设置指令。构建指令用于构建 p_w_picpath 其指定的操作不会在运行 p_w_picpath 的容器上执行;设置指令用于设置 p_w_picpath 的属性,其指定的 操作将在运行 p_w_picpath 的容器中执行。

一般的,Dockerfile 分为四部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时 执行指令。

# Thisdockerfile uses the ubuntu p_w_picpath

# VERSION 2 - EDITION 1

# Author: docker_user

# Command format: Instruction [arguments / command] ..

# Base p_w_picpath to use, this must be set as the first line FROM ubuntu

# Maintainer: docker_user<docker_user at email.com> (@docker_user) MAINTAINER docker_user docker_user@email.com

# Commands to update the p_w_picpath

RUNecho"debhttp://archive.ubuntu.com/ubuntu/raringmainuniverse">> /etc/apt/sources.list

RUN apt-get update && apt-get install -y nginx

RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf

# Commands when creating a new container CMD /usr/sbin/nginx

其中,一开始必须指明所基于的镜像名称,接下来推荐说明维护者信息。

后面则是镜像操作指令,例如RUN指令, RUN指令将对镜像执行跟随的命令。每运 行一条RUN指令,镜像添加新的一层,并提交。

最后是CMD指令,来指定运行容器时的操作命令。

dockerfile 指令

指令的一般格式为INSTRUCTION arguments,指令包括FROM MAINTAINER RUN

等。

1FROM(指定基础 p_w_picpath

构建指令,必须指定且需要在 Dockerfile 其他指令的前面。后续的指令都依赖于该指令指定  p_w_picpathFROM 指令指定的基础 p_w_picpath 可以是官方远程仓库中的,也可以位于本地仓库。

该指令有两种格式:
FROM <p_w_picpath>

指定基础 p_w_picpath 为该 p_w_picpath 的最后修改的版本。 

或者:

FROM <p_w_picpath>:<tag>

2MAINTAINER(用来指定镜像创建者信息)

构建 image 制作写入 image  image  docker inspect 命令时,输出中有相应的字段记录该信息。

格式:

MAINTAINER <name>

3RUN(安装软件用)

构建指令,RUN 可以运行任何被基础 p_w_picpath 支持的命令。如基础 p_w_picpath 选择了 ubuntu,那 么软件管理部分只能使用 ubuntu 的命令。

该指令有两种格式:
RUN <command> (the command is run in a shell - `/bin/sh -c`) 
RUN ["executable", "param1", "param2" ... ]  (exec form)

4CMD(设置 container 启动时执行的操作)

该指令有三种格式:

设置指令,用于 container 启动时指定的操作。该操作可以是执行自定义脚本,也可以是执 行系统命令。


CMD ["executable","param1","param2"]    使用exec执行,推荐方式;
CMD command param1 param2  在/bin/sh 中执行,提供给需要交互的应用;

 Dockerfile 指定了 ENTRYPOINT,那么使用下面的格式:

CMD ["param1","param2"]  提供给ENTRYPOINT的默认参数;

ENTRYPOINT 指定的是一个可执行的脚本或者程序的路径,该指定的脚本或者程序 将会以 param1  param2 作为参数执行。所以如果 CMD 指令使用上面的形式,那 么 Dockerfile 中必须要有配套的 ENTRYPOINT

 

指定启动容器时执行的命令,每个 Dockerfile 只能有一条CMD命令。如果指定了多条 命令,只有最后一条会被执行。

如果用户启动容器时候指定了运行的命令,则会覆盖掉CMD指定的命令。

5ENTRYPOINT(设置 container 启动时执行的操作) 设置指令,指定容器启动时执行的命令,可以多次设置,但是只有最后一个有效。

两种格式:
ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2


每个 Dockerfile 中只能有一个ENTRYPOINT,当指定多个时,只有最后一个起效。

 

该指令的使用分为两种情况,一种是独自使用,另一种和 CMD 指令配合使用。 当独自使用时,如果你还使用了 CMD 命令且 CMD 是一个完整的可执行的命令,那  CMD 指令和 ENTRYPOINT 会互相覆盖只有最后一个 CMD 或者 ENTRYPOINT 有效。

例如: CMD 指令将不会被执行,只有 ENTRYPOINT 指令被执行

CMD echo “Hello, World!”

ENTRYPOINT ls -l

另一种用法和 CMD 指令配合使用来指定 ENTRYPOINT 的默认参数,这时 CMD 令不是一个完整的可执行命令仅仅是参数部分ENTRYPOINT 指令只能使用 JSON 方式指定执行命令,而不能指定参数。

例如:

 

FROM ubuntu CMD ["-l"]

ENTRYPOINT ["/usr/bin/ls"]

 

6USER(设置 container 容器的用户,默认是 root 用户) 格式为USER daemon

指定运行容器时的用户名或 UID,后续的RUN也会使用指定用户。 当服务不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的 用户,例

如: RUN groupadd -r postgres&&useradd -r -g postgrespostgres

例如: 指定 memcached 的运行用户

ENTRYPOINT ["memcached"]
USER daemon


ENTRYPOINT ["memcached", "-u", "daemon"]

7EXPOSE(指定容器需要映射到宿主机器的端口) 

格式为

 EXPOSE <port>[<port>...]

设置指令,该指令会将容器中的端口映射成宿主机器中的某个端口。当你需要访问容器的时 候,可以不是用容器的 IP 地址而是使用宿主机器的 IP 地址和映射后的端口。 要完成整个操作需要两个步骤,首先在 Dockerfile 使用 EXPOSE 设置需要映射的容器端口, 然后在运行容器的时候指定-p 选项加上 EXPOSE 设置的端口,这样 EXPOSE 设置的端口号会 被随机映射成宿主机器中的一个端口号。也可以指定需要映射到宿主机器的那个端口,这时 要确保宿主机器上的端口号没有被使用。EXPOSE 指令可以一次设置多个端口号,相应的运 行容器的时候,可以配套的多次使用-p 选项。

例如: 映射一个端口

EXPOSE port1

# 相应的运行容器使用的命令

docker run -p port1 p_w_picpath

 

例如: 映射多个端口


EXPOSE port1 port2 port3

# 相应的运行容器使用的命令

docker run -p port1 -p port2 -p port3 p_w_picpath

# 还可以指定需要映射到宿主机器上的某个端口号

docker run -p host_port1:port1 -p host_port2:port2 -p host_port3:port3 p_w_picpath

端口映射是 docker 比较重要的一个功能,原因在于我们每次运行容器的时候容器的 IP 地址不能指定而是在桥接网卡的地址范围内随机生成的宿主机 IP 地址是固 定的,我们可以将容器的端口的映射到宿主机器上的一个端口,免去每次访问容器 中的某个服务时都要查看容器的 IP 的地址。

对于一个运行的容器,可以使用 docker port 加上容器中需要映射的端口和容器的 ID

来查看该端口号在宿主机器上的映射端口。

 

8ENV(用于设置环境变量)

构建指令,指定一个环境变量,会被后续RUN指令使用,并在容器运行时保持。

格式:
ENV <key> <value>

设置了后,后续的 RUN 命令都可以使用,container 启动后,可以通过 docker inspect 查看这个环境变以通过在 docker run --env key=value 时设置或改环境变。 假如你安装了 JAVA 程序需要设置 JAVA_HOME那么可以在 Dockerfile 中这样写:

ENV JAVA_HOME /path/to/java/dirent

再例如:

ENV PG_MAJOR 9.3

ENV PG_VERSION 9.3.4

RUN curl http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgress 

ENV PATH  /usr/local/postgres-$PG_MAJOR/bin:$PATH

 9ADD(从 src 复制文件到 container  dest 路径)

构建指令,所有拷贝到 container 中的文件和文件夹权限为 0755uid gid 0 如果是一个目录,那么会将该目录下的所有文件添加到 container 中,不包括目录; 如果格式 docker 压缩 如果<src>是文件且<dest>中不使用斜杠结束,则会将<dest>视为文件,<src>的内容会写入

<dest> 如果<src>是文件且<dest>中使用斜杠结束,则会<src>文件拷贝到<dest>目录下。

格式:
ADD <src> <dest>

该命令将复制指定的<src>到容器中的<dest>

其中<src>可以是 Dockerfile 所在目录的一个相对路径;也可以是一个 URL;还可以 是一个 tar  文件(自动解压为目录)

<dest> container 中的绝对路径

10COPY

格式为 

COPY <src><dest>

复制本地主机的<src>(为 Dockerfile 所在目录的相对路径)到容器中的<dest>


11VOLUME(指定挂载点) 设置指令,使容器中的一个目录具有持久化存储数据的功能,该目录可以被容器本身使用, 也可使使用的 AUFS能持据, 当容器关闭后,所有的更改都会丢失。当容器中的应用有持久化数据的需求时可以在 Dockerfile 中使用该指令。

格式:
VOLUME ["<mountpoint>"]

例如:FROM  base VOLUME ["/tmp/data"]

运行通过该 Dockerfile 生成 p_w_picpath 的容器,/tmp/data 目录中的数据在容器关闭后,

里面的数据还存在。例如另一个容器也有持久化数据的需求,且想使用上面容器共 享的/tmp/data 目录,那么可以运行下面的命令启动一个容器:

docker run -t -i -rm -volumes-from container1 p_w_picpath2 bash

container1 为第一个容器的 IDp_w_picpath2 为第二个容器运行 p_w_picpath 的名字。

 

12WORKDIR(切换目录)

设置指令( cd ) RUN,CMD,ENTRYPOINT 后续的RUN CMDENTRYPOINT指令配置工作目录。

格式:

WORKDIR /path/to/workdir

例如: 在 /p1/p2 下执行 vim a.txt

WORKDIR /p1 

WORKDIR p2

RUN vim a.txt

可以使用多个WORKDIR指令,后续命令如果参数是相对路径,则会基于之前命令指定的 路径。

例如 

WORKDIR /a

 WORKDIR b

 WORKDIR c

RUN pwd

则最终路径为/a/b/c

13ONBUILD(在子镜像中执行)


ONBUILD <Dockerfile关键字>

ONBUILD 指定的命令在构建镜像时并不执行,而是在它的子镜像中执行。

 

格式为

ONBUILD[INSTRUCTION]  。

配置当所创建的镜像作为其它新创建镜像的基础镜像时,所执行的操作指令。 例如,Dockerfile 使用如下的内容创建了镜像p_w_picpath-A

[...]

ONBUILD ADD . /app/src

ONBUILD RUN /usr/local/bin/python-build --dir /app/src

[...]

如果 image-A  建新的镜像时 Dockerfile 中使用FROM image-A指定 时,会自动执行 ONBUILD指令内容。

等价于在后面添加了两条指令。

FROM p_w_picpath-A

#Automatically run the following ADD . /app/src

RUN /usr/local/bin/python-build --dir /app/src

使用  ONBUILD    指令的镜像,推荐在标签中注明,例如  ruby:1.9-onbuild    

 

编写完成 Dockerfile 之后,可以通过 docker build  命令来创建镜像。

基本的格式为 docker build [选项] 路径,该命令将读取指定路径下的 Dockerfile,并将该路径 下所有内容发送给 Docker 服务端,由服务端来创建镜像。因此一般建议放置 Dockerfile 目录为空目录。

要指定镜像的标签信息,可以通过  -t    选项,例如

$ sudodocker build –tmyrepo/myapp/tmp/test1/

docker 应用案例:使用 dockerfile 创建 sshd 镜像模板并提供 http 访问应用

1) 创建一个 sshd_dockerfile 工作目录

wKioL1mJd7-xz6bZAAASAGTj-EM681.png

编辑 run.sh 文件

[root@localhost sshd_dockerfile]# cat  run.sh 
#!/bin/bash
/usr/sbin/apachectl -k restart
/usr/sbin/sshd -D


在主机上生成 ssh 秘钥对,并创建 authorized_keys 文件

wKiom1mJd8DCsw2_AAA4MpHW6yA341.png

wKiom1mJd8Dj2PfJAAARtco1WC0540.png

2) 编写 Dockerfile

wKioL1mJd8Djtj0MAAAGADhDh1M407.png

FROM   cf2c3ece5e41
MAINTAINER from duyuheng@example.com 
RUN yum install -y openssh-server sudo httpd
RUN useradd admin
RUN echo "admin:admin" | chpasswd
RUN echo "admin   ALL=(ALL)       ALL" >> /etc/sudoers
RUN ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key
RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
RUN mkdir -p /var/run/sshd
RUN mkdir -p /home/admin/.ssh
RUN  sed -i "s/#ServerName/ServerName/g" /etc/httpd/conf/httpd.conf
RUN sed  -i 's/session reqired pam_loginuid.so/#session reqired pam_loginuid.so/g' /etc/pam.d/sshd
ADD authorized_keys /home/admin/.ssh/authorized_keys
ADD run.sh /run.sh
RUN chmod 775 /run.sh
CMD ["apachectl -k start"]
EXPOSE 22  80
CMD ["/run.sh"]


以上参数详解:FROM centos:centos6 选择一个已有的 os 镜像作为基础,(可以是镜像ID

MAINTAINER 镜像的作者

RUN yum install -y openssh-server sudo 安装 openssh-server  sudo 软件包 添加测试用户 admin,密码 admin,并且将此用户添加到 sudoers 

RUN useradd admin

RUN echo "admin:admin" | chpasswd

RUN echo "adminALL=(ALL)ALL" >> /etc/sudoers 下面这两句比较特殊,在 centos6 上必须要有,否则创建出来的容器 sshd 不能登录 RUN ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key

RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key

注意:centos7 上必须要有,否则创建出来的容器 sshd 不能登录 RUN ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key

RUN ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key RUN ssh-keygen -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key

将公钥信息上传到远程连接用户的宿主目录的.ssh

ADDauthorized_keys /home/admin/.ssh/authorized_keys

启动 sshd 服务并且暴露 22 端口 RUN mkdir /var/run/sshd EXPOSE 22 80

CMD ["/run.sh"]也可以写成这种方式 CMD ["/usr/sbin/sshd", "-D"]

 

 sshd_dockerfile 目录下,使用 dockerbuild 命令来创建镜像,注意:在最后还有一个”.”


表示使用当前目录中的 dockerfile

[root@localhost sshd_dockerfile]# docker build --no-cache -t "centos:httpdv1" .

 

Sending build context to Docker daemon 4.608 kB

Step 1 : FROM cf2c3ece5e41

 ---> cf2c3ece5e41

Step 2 : MAINTAINER from duyuheng@example.com

 ---> Running in 69e7b58c714b

 ---> afd3bb65c464

Removing intermediate container 69e7b58c714b

Step 3 : RUN yum install -y openssh-server sudo httpd

 ---> Running in e09ba3be13e1

Loaded plugins: fastestmirror, ovl

Setting up Install Process

Step 4 : RUN useradd admin

 ---> Running in 2fa6ba088b5f

 ---> 576ac8ffa565

Removing intermediate container 2fa6ba088b5f

Step 5 : RUN echo "admin:admin" | chpasswd

 ---> Running in 68ee8b40e46e

 ---> c3c9f679f28a

Removing intermediate container 68ee8b40e46e

Step 6 : RUN echo "admin   ALL=(ALL)       ALL" >> /etc/sudoers

 ---> Running in 436c681a1f54

 ---> 866926b60ebd

Removing intermediate container 436c681a1f54

Step 7 : RUN ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key

 ---> Running in 58fbda53d736

Enter passphrase (empty for no passphrase): Enter same passphrase again: Generating public/private dsa key pair.

Your identification has been saved in /etc/ssh/ssh_host_dsa_key.

Your public key has been saved in /etc/ssh/ssh_host_dsa_key.pub.

The key fingerprint is:

bc:3a:0b:e0:6c:9b:4e:dc:71:fe:be:48:1e:e7:d0:0f root@68a1f3cfce80

The key's randomart p_w_picpath is:

+--[ DSA 1024]----+

|                 |

|                 |

|                 |

|       .         |

|  . . . S        |

| + o + . .       |

|  * o = E        |

| o o +.O o       |

| .+   =+=..      |

+-----------------+

 ---> 281438c8037b

Removing intermediate container 58fbda53d736

Step 8 : RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key

 ---> Running in 0ecd8e232846

Enter passphrase (empty for no passphrase): Enter same passphrase again: Generating public/private rsa key pair.

Your identification has been saved in /etc/ssh/ssh_host_rsa_key.

Your public key has been saved in /etc/ssh/ssh_host_rsa_key.pub.

The key fingerprint is:

66:ee:95:ce:62:a9:6a:b5:cb:cb:5d:d6:6f:37:98:3e root@68a1f3cfce80

The key's randomart p_w_picpath is:

+--[ RSA 2048]----+

|                 |

|                 |

|                 |

|                 |

|        S        |

|      .+   o     |

|     . ...= . o  |

|    .o.o+*   E...|

|   ...*=o.o .oo..|

+-----------------+

 ---> 4cce287f3355

Removing intermediate container 0ecd8e232846

Step 9 : RUN mkdir -p /var/run/sshd

 ---> Running in 53d5bd775f06

 ---> 554708e435ca

Removing intermediate container 53d5bd775f06

Step 10 : RUN mkdir -p /home/admin/.ssh

 ---> Running in 3fa187c01969

 ---> 993a916d49d4

Removing intermediate container 3fa187c01969

Step 11 : RUN sed -i "s/#ServerName/ServerName/g" /etc/httpd/conf/httpd.conf

 ---> Running in 6cddc070a431

 ---> cb1c8fb1c4f5

Removing intermediate container 6cddc070a431

Step 12 : RUN sed  -i 's/session reqired pam_loginuid.so/#session reqired pam_loginuid.so/g' /etc/pam.d/sshd

 ---> Running in bda627f5cc91

 ---> f0ad9f29d4b2

Removing intermediate container bda627f5cc91

Step 13 : ADD authorized_keys /home/admin/.ssh/authorized_keys

 ---> 5d18b5209a56

Removing intermediate container e74b55682dc9

Step 14 : ADD run.sh /run.sh

 ---> c4df0d5d5859

Removing intermediate container 4277118320ba

Step 15 : RUN chmod 775 /run.sh

 ---> Running in 9b12d5244fa7

 ---> 483c258c7efc

Removing intermediate container 9b12d5244fa7

Step 16 : CMD apachectl -k start

 ---> Running in 4793a4f00bce

 ---> f88e170cb2ba

Removing intermediate container 4793a4f00bce

Step 17 : EXPOSE 22 80

 ---> Running in 9b0cc5a09724

 ---> 7b400d79c396

Removing intermediate container 9b0cc5a09724

Step 18 : CMD /run.sh

 ---> Running in 860502160c5a

 ---> 394d8dd6802d

Removing intermediate container 860502160c5a

Successfully built 394d8dd6802d


执行 docker p_w_picpaths 查看新生成的镜像

[root@localhost sshd_dockerfile]# docker   p_w_picpaths

wKioL1mK1xiRPU0OAAAYwV08wno541.png


REPOSITORYTAGIMAGE IDCREATEDSIZE


使用刚才建好的镜像运行一个容器,将容器的端口映射到主机的 10122

[root@localhost ~]# docker run -dit --name webserver1 -p 10122:22 -p 80:80 --restart=always centos:httpdv1

61d165e377dbe93358a381a482e7e126f104f50b4492c22265606ac5a2fe9954

[root@localhost ~]# docker ps

wKiom1mK2G6SrZTlAAAeGU8IRq0729.png

 在宿主主机打开一个终端,连接刚才新建的容器

wKioL1mK2daj5jZUAAAvfbTfYWo566.png

注:admin 用户是容器中的用户,192.168.1.107 地址是宿主机的地址。 测试 sudo 执行授权命令:

wKioL1mK2qGDhtX_AABHvKkGWyU000.png

dockerinspect 查看容器的 ip 地址,在宿主机上直接 ssh 连接容器

wKioL1mK4cPw5xBqAAAdK5YZkMM151.png