使用Dockerfile创建镜像
- Dockerfile是一个文本格式的配置文件,我们可以利用Dockerfile来快速的创建一个自定义的镜像。
基本结构
- Dockerfile由一行命令语句组成,并且支持以#开头的注释
- 一般包括四个部分:基础镜像信息,维护者信息,镜像操作指令,容器启动时执行指令,如下一个案例
# This Dockerfile uses the ubuntu image
# VERSION 2 - EDITION 1
# Author: docker_user
# Command format: Instruction [arguments / command] ..
# Base image 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 image
RUN echo "deb http://archive.ubuntu.com/ubuntu/ raring main universe" >> /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
- 如上是一个官网的Demo,一开始指定所基于的镜像名称,之后是维护者的信息,后面才是镜像操作的指令,例如RUN指令将对镜像执行跟随在后面的命令,CMD用来指定运行容器时候的操作命令。
- 如下是一个更复杂一点的案例,基于buildpack-deps:jessie-scm基础镜像,安装Golang相关环境,制作一个GO语言的运行环境镜像(先看看就行):
FROM buildpack-deps:jessie-scm
# gcc for cgo
RUN apt-get update && apt-get install -y --no-install-recommends \
g++ \
gcc \
libc6-dev \
make \
&& rm -rf /var/lib/apt/lists/*
ENV GOLANG_VERSION 1.6.3
ENV GOLANG_DOWNLOAD_URL https://golang.org/dl/go$GOLANG_VERSION.linux-amd64.tar.gz
ENV GOLANG_DOWNLOAD_SHA256 cdde5e08530c0579255d6153b08fdb3b8e47caabbe717bc7bcd
7561275a87aeb
RUN curl -fsSL "$GOLANG_DOWNLOAD_URL" -o golang.tar.gz \
&& echo "$GOLANG_DOWNLOAD_SHA256 golang.tar.gz" | sha256sum -c - \
&& tar -C /usr/local -xzf golang.tar.gz \
&& rm golang.tar.gz
ENV GOPATH /go
ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH
RUN mkdir -p "$GOPATH/src" "$GOPATH/bin" && chmod -R 777 "$GOPATH"
WORKDIR $GOPATH
COPY go-wrapper /usr/local/bin/
指令说明
- FROM
- 指定所创建镜像的基础镜像,如果本地不存在,默认去Docker Hub上下载,格式:FROM < image>
- 任何一个Dockerfile中第一条指令必须是FROM,并且,如果在同一个Dockerfile中创建多个镜像,可以用多个FROM指令
- MAINTAINER
- 指定维护者信息,格式MAINTAINER< name>。信息会写入生成镜像的Author属性域中例如:
MAINTAINER ljmadmin@docker.com
- RUN
- 运行指定命令格式如下
- 上面第一个命令默认将在shell中断中运行,即 /bin/sh -C ,后面的使用exec执行不会启动shell环境
- 每一条RUN指令将在当前镜像的基础上执行指定的命令,并且提交为新的进行,当命令比较长的时候,可以用\ 来换行,比如:
RUN <command> 或者 RUN ["executable", "param1","param2"],
//案例
RUN apt-get update \&& apt-get install -y libsnappy-dev zliblg-dev libbz2-dev \&& rm -rf /var/cache/apt
- CMD
- CMD指令用来指定启动容器时候默认执行的命令,他支持三种格式:
- CMD[“executable”, “param1”, “param2”] 使用exec执行,是推荐使用的方式
- CMD command param1 param2 在/bin/sh 中执行,提供给需要交互的应用
- CMD [“param1”, “param2”]提供给ENTRYPOINT的默认数
- 每个DOckerfile只能有一条CMD命令,如果指定多条,最后一条覆盖之前的
- LABEL
- LABEL指令用来指定生成镜像的元数据标签信息
- 格式为如下例如
LABEL<key> = <value><key>=<value>....
//案例
LABEL version="1.0"
LABEL description="This text illustrates \ that label-values can span multiple lines."
- EXPOSE
- 声明镜像内服务所监听的端口
- 格式如下。 例如
EXPOSE <port>[ <port>......]
//案例
EXPOSE 22 80 8443
- 改指令只是起到声明作用,不会自动完成端口映射
- 启动容器时候需要使用-P,Docker主机会自动分配一个宿主机临时端口转发到指定的端口,使用-p,则可以具体的指定哪个宿主机本地端口会映射过来。
- ENV
- 指定环境变量,在镜像生成过程中会被后续RUN指令使用,在镜像启动的容器中也会存在
- 格式…。如下:
ENV <key><value> 或者 EVN <key>=<value>
//案例
ENV PG_MAJOR 9.3
ENV PG_VERSION 9.3.4
RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/
postgress && …
ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH
- 指令指定的环境变量在运行时可以被覆盖掉,比如docker run --evn< key>=< value>built_image
- ADD
- 该命令将复制指定额< src> 路径下的内容到容器中的< dest> 路径下,格式如下
- 其中< src> 可以是Dockerfile所在的目录的一个相对路径,也可以是一个URL,还可以是一个tar文件。< desc>可以使镜像内部的绝对路径,或者相对于工作目录的相对路径。
ADD <src><desc>
- COPY
- 格式如下,复制本地主机的< src> (为Dockerfile所在目录的相对路径,文件,或者目录) 下的内容 到镜像中的< dest> 下。目标路径不存在时候回自动创建 。路径支持正则,当使用本地目录为源目录时候,推荐使用COPY
COPY<src><desc>
- ENTRYPOINT
- 指定镜像的默认入口命令,该入口命令会在启动容器时候作为命令执行,所有传入值作为改命令的参数,支持如下两种格式
ENTRYPOINT ["executable", "param1", "param2"](exec调用执行)
ENTRYPOINT command param1 param2(shell中执行)
- 每个Dockerfila中只能有一个ENTRYPOINT,当指定过个时候,只有最后一个有效,在运行时候可以被–entrypoint参数覆盖掉,如docker run–entrypoint
- VOLUME
- 创建一个数据卷挂载点, 可以从本地主机或者其他容器挂载数据卷,一般用来存放数据库和需要保存的数据等。格式如下
VULUME ["/data"]
- USER
- 指定运行容器时候的用户名或者UID,后续的RUN等指令也会使用指定的用户身份格式如下:
USER daemon
//案例
RUN groupadd -r postgres && useradd -r -g postgres postgres
- 需要临时获取管理员权限可以使用gosu或者sudo
- WORKDIR
- 为后续的RUN,CMD和ENTRYPOINT指令配置工作目录,格式如下
WORKDIR /path/to/workdir
//案例
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
- 如上案例,可以使用多个WORKDIR指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。最终的路径为/a/b/c
- ARG
- 指定一些镜像内使用的参数(例如版本号信息等),这些参数在执行docker build命令时以下格式传入
ARG<name>[=<default value>]
//案例
docker build--build-arg<name>=<value>
- ONBUILD
- 配置当所有创建的镜像作为其他镜像的基础镜像时,所执行的创建操作指令,格式如下:
ONBUILD [INSTRUCTION]
//Dockerfile使用如下内容创建镜像image-A
[...]
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bing/python-build --dir /app/src
[...]
- 如果基于image-A创建新的镜像时候,新的Dockerfile使用FROM image-A指定基础进行,会自动执行ONBUILD指令的内容,等价于在后面添加了两条指令,如下:
FROM image-A
#Automatically run the following
ADD . /app/src
RUN /usr/local/bin/python-build --dir /app/src
- 使用ONBUILD指令的镜像,推荐在边去中注明,例如ruuby:1.9-onbuild
- STOPSIGNAL
- 指定所创建的镜像启动的容器接受退出的信号值,例如:
STOPSIGNAL signal
- HEALTHCHECK
- 配置所启动容器如何进行健康检查(如何判断健康与否),自Docker1.12开始支持,格式如下:
HEALTHCHECK [OPTIONS] CMS command :根据执行命令返回值是否为0 判断
HEALTHCHECK NONE : 禁止基础镜像中的监看检查
- OPTION参数支持如下:
- __interval=DURATION(默认30s):过多久检查一次
- __timeout=DURATION(默认30s):每次检查等待结果的超时
- __retries=N(默认为3):如果失败,重试几次才最终确定失败。
创建镜像
- 编写完Dockerfile后,可以通过docker build命令来创建镜像,基础格式如下:
docker build [选项]
- 如上命令将读取指定路径下(包括子目录)的Dockerfile文件,并将该路劲下所有内容发送给Docker 服务端,由服务端来创建镜像,因此除非生成镜像需要,否则一般建议放置Dockerfile的目录为空目录。
- 如果使用非内容路径下Dockerfile,可以通过-f 选项指定其他路径
- 要指定生成镜像的便签可以用-t 选项
- 案例:指定Dockerfile路径/tmp/docker_builder/,并且生成镜像标签为build_repo/first_image,命令如下
docker build -t build_repo/first_image /temp/docker_builder
使用.dockerignore文件
- 上说的,Dockerfile路径下的所有文件都会发到Docker服务端打包,那肯定有响应的规避措施,
- 我们通过.dockerignore文件(没一行添加一条匹配模式)来让Docker忽略匹配模式路径下的目录和文件。如下:
#comment*/temo**/*/temp*tmp?~*
Dockerfile实战测试
- 以下将分别通过docker commit命令方式,Dockerfile的方式分别为镜像添加SSH服务并且生成新的镜像文件,来对象两者的区别,
通过docker commit 方式创建镜像
- Docker提供了docker commit 命令,支持用户提交自己对指定容器的修改,并且生成新的镜像在本地。格式如下:
docker commit CONTAINER [REPOSITORY[:TAG]]
- 如下步骤依次执行:
//使用ubuntu:lasted
docker run -it ubuntu:lasted /bin/bash
//更新apt缓存,并安装openssh-server
apt-get update; apt-get install openssh-server -y
//如需正常启动SSH服务,则目录/var/run/sshd必须存在,手动创建,并启动SSH服务
mkdir -p /var/run/sshd
/usr/sbin/ssh -D &
//修改SSH服务的安全登录配置,取消pam登录限制
sed -ri 's/session required pam_loginuid.so/#session required pam_loginuid.so/g' /etc/pam.d/sshd
//在root账户下创建.ssh目录,并负责需要登录的公钥(公钥信息一般为本机主机用户目录下.ssh/id_rsa.pub文件,可由ssh-keygen-t rsa命令生成)到authorized_keys文件中:
mkdir root/.ssh
vi /root/.ssh/authorized_keys
//创建自动启动ssh服务的可执行文件run.sh,并添加权限:
vi /run.sh
chmod +x run.sh
//编辑内容
#!/bin/bash
/usr/sbin/sshd -D
//退出容器
exit
//保存镜像
docker commit [CONTAINER ID] sshd:ubuntu
//使用docker images查看本地生成的镜像sshd:ubuntu,目前拥有镜像信息如下截图
//使用镜像
docker run -p 10022:22 -d ssh:ubuntu /run.sh
//启动成功后可以在宿主机上看到容器运行的详细信息
docker ps
//可以通过该宿主机ip访问,通过ssh 10022 端口登录容器
ssh 192.168.*.* -p 10022
使用Dockerfile创建
- 依次按如下步骤
//创建工作目录sshd_ubuntu工作目录
mkdir sshd_ubuntu
//在其中创建Dockerfile和run.sh文件
cd /sshd_ubuntu/
touch Dockerfile run.sh
//编写run.sh脚本和authorized_key文件
#!/bin/bash
/usr/sbin/sshd -d
//在宿主机上生成SSH秘钥对,并创建authorized_keys文件:
ssh-keygen -t rsa
....
cat ~/.ssh/id_rsa.pub > authorized_keys
- 编写Dockerfile,下面是Dockerfile的内容以及部分的解释信息,可以对比docker commit 命令创建的过程,操作基本一致:
#设置基础镜像
FROM ubuntu:latest
#提供一些作者信息
MAINTAINER ljmadmin (645121107@qq.com)
#下面开始运行更新命令
RUN apt-get update
#安装ssh服务
RUN apt-get install -y openssh-server
RUN mkdir -p /var/run/sshd
RUN mkdir -p /root/.ssh
#取消pam限制
RUN sed -ri 's/session required pam_loginuid.so/#session required pam_loginuid.so/g' /etc/pam.d/sshd
#复制配置文件到相应位置,并赋予可执行权限
ADD authorized_keys /root/.ssh/authorized_keys
ADD run.sh /run.sh
RUN chmod 755 /run.sh
#开放端口
EXPOSE 22
#设置自启动命令
CMD ["/run.sh"]
- 创建镜像:在sshd_ubuntu目录下使用docker build命令创建镜像,
cd sshd_ubuntu
docker build -t ssh:Dockerfile .
- 查看本地ssh:Dockerfile镜像已经存在:
- 测试启动镜像运行容器效果与上面一致
总结
- Dockerfile使用前需要熟悉每个命令,多实践,自己写一些简单的案例测试,弄清楚原理在写,Docker Hub官方仓库有很多优秀镜像对应的Dockerfile可以借鉴学习
- 创建原则有如下几个:
- 精简镜像用途:
- 选合适基础镜像
- 提供足够清晰的命令注释和维护者信息
- 正确使用版本号码
- 减少镜像层数
- 及时删除临时文件和缓存文件
- 提高生成速度
- 调整合理的指令顺序
- 减少外部源干扰
上一篇:Docker中数据管理
下一篇:Docker容器实战思维