常用命令
类型 | 命令 |
---|---|
基础镜像 | FROM |
元数据 | LABEL |
镜像操作指令 | RUN、COPY、ADD、EXPOSE、WORKDIR、ONBUILD、USER、VOLUME等 |
容器启动时执行指令 | CMD、ENTRYPOINT |
FROM
用来指定基础镜像,然后通过在基础镜像上构建新的镜像,基础镜像一般有远程或本地仓库。并且Dockerfile文件第一行必须的FROM指令,如果一个Dockerfile需要创建多个镜像,可以使用多个FROM指令。
尽量使用官方的baseimage
LABEL
可以理解为代码中的注释
RUN
运行所有基础镜像能支持的命令,同样也可以使用多条RUN指令,可以使用\来换行
反斜线换行
安装完成后清理缓存
WORKDIR
指定RUN、CMD、ENTRYPIONT指定的命令的运行目录。可以使用多个WORKDIR指令,后续参数如果是相对路径,则会基于之前的命令指定的路径。
WORKDIR /path/to/workdir
ADD©
相同
COPY 命令是为最基本的用法设计的,概念清晰,操作简单。而 ADD 命令基本上是 COPY 命令的超集,可以实现一些方便、酷炫的拷贝操作。
- 对于目录而言,COPY 和 ADD 命令具有相同的特点:只复制目录中的内容而不包含目录自身。
ADD <源路径>... <目标路径>
COPY <源路径>... <目标路径>
<源路径>可以是多个,甚至可以是通配符,其通配符规则要满足 Go 的 filepath.Match 规则,如:
ADD hom* /mydir/
COPY hom?.txt /mydir/
-
复制指定的源文件、目录、URL到容器的指定目录中。所有拷贝到container中的文件和文件夹权限为0755,uid和gid为0。
差异
- 如果源文件是可识别的压缩格式,ADD 命令会帮忙解压缩;
- COPY 命令区别于 ADD 命令的一个用法是在 multistage 场景下。在 multistage 的用法中,可以使用 COPY 命令把前一阶段构建的产物拷贝到另一个镜像中。
- 从 url 拷贝文件到镜像中,但官方不建议这么做。建议使用wget或curl。
ENV
这个指令很简单,就是设置环境变量而已,无论是后面的其它指令,如 RUN,还是运行时的应用,都可以直接使用这里定义的环境变量。
ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...
USER
用于指定运行镜像所使用的用户
使用USER指定用户时,可以使用用户名、UID 或 GID,或是两者的组合。
USER user
USER user:group
USER uid
USER uid:gid
USER user:gid
USER uid:group
RUN、CMD、ENTRYPOINT区别
RUN 在构建的时候执行,并生成一个新的镜像,CMD和ENTRYPOINT 是在容器运行的时候执行,在构建时不进行任何操作。
一个Dockerfile可以有多个RUN,但只允许有一个 CMD或ENTRYPOINT 命令,多指定时会覆盖前面的设置,而只执行最后的 CMD或ENTRYPOINT 指令。
ENTRYPOINT 与 CMD 非常类似,不同的是通过 docker run执行的命令不会覆盖 ENTRYPOINT,而 docker run命令中指定的任何参数,都会被当做参数再次传递给 ENTRYPOINT。
EXPOSE
为构建的镜像设置监听端口,使容器在运行时监听。
EXPOSE <port> [<port>...]
假设有一个python的小程序,app.py文件
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return "hello docker"
if __name__ == '__main__':
app.run()
python app.py
* Serving Flask app "app" (lazy loading)
* Environment: production
WARNING: Do not use the development server in a production environment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
访问http://127.0.0.1:5000/,可以看到服务成功启动,hello docker。
FROM python
RUN pip install flask
WORKDIR /app
COPY app.py .
EXPOSE 5000
CMD ["python", "app.py"]
两种方式的区别是:
-P : 是容器内部端口随机映射到主机的高端口。
-p : 是容器内部端口绑定到指定的主机端口。
docker build -t flask-demo .
docker run -p 5000:5000 -d b0720c4f347c
ONBUILD
ONBUILD用于配置当前所创建的镜像作为其它新创建镜像的基础镜像时,所执行的操作指令。这个镜像创建后,如果其它镜像以这个镜像为基础,会先执行这个镜像的ONBUILD命令。
ONBUILD [INSTRUCTION]
FROM node:0.12.6
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
ONBUILD COPY package.json /usr/src/app/
ONBUILD RUN npm install
基于上面构建一个名为node-onbuild父镜像
FROM node-onbuild
COPY . /usr/src/app
CMD [ "npm", "start" ]
会发现父镜像dockerfile的内容中ONBUILD部分
ONBUILD COPY package.json /usr/src/app/
ONBUILD RUN npm install
是在构建子镜像的时候才执行的
最佳实践
减少层数
一次RUN指令形成新的一层,尽量Shell命令都写在一行,减少镜像层。
FROM centos:7
MAINTAINER www.ctnrs.com
RUN yum install epel-release -y
RUN yum install -y gcc gcc-c++ make -y
RUN wget http://docs.php.net/distributions/php-5.6.36.tar.gz
RUN tar zxf php-5.6.36.tar.gz
RUN cd php-5.6.36
RUN ./configure --prefix=/usr/local/php
RUN make -j 4
RUN make install
EXPOSE 9000
CMD ["php-fpm"]
改成
FROM centos:7
MAINTAINER www.ctnrs.com
RUN yum install epel-release -y && \
yum install -y gcc gcc-c++ make
RUN wget http://docs.php.net/distributions/php-5.6.36.tar.gz && \
tar zxf php-5.6.36.tar.gz && \
cd php-5.6.36 && \
./configure --prefix=/usr/local/php && \
make -j 4 && make install
EXPOSE 9000
CMD ["php-fpm"]
清理无用数据
一次RUN形成新的一层,如果没有在同一层删除,无论文件是否最后删除,都会带到下一层,所以要在每一层清理对应的残留数据,减小镜像大小。
FROM centos:7
MAINTAINER www.ctnrs.com
RUN yum install epel-release -y && \
yum install -y gcc gcc-c++ make gd-devel libxml2-devel \
libcurl-devel libjpeg-devel libpng-devel openssl-devel \
libmcrypt-devel libxslt-devel libtidy-devel autoconf \
iproute net-tools telnet wget curl && \
yum clean all && \
rm -rf /var/cache/yum/*
RUN wget http://docs.php.net/distributions/php-5.6.36.tar.gz && \
tar zxf php-5.6.36.tar.gz && \
cd php-5.6.36 && \
./configure --prefix=/usr/local/php \
make -j 4 && make install && \
cd / && rm -rf php*
减少网络传输时间
最好在内部有一个存放软件包的地方,最好的方法就是建立php-composer、maven、npm等私有仓库,减少网络传输时间,提高镜像构建速度。
使用多阶段构建
使用多阶段构建,您可以在Dockerfile中使用多个FROM语句。每条FROM指令都可以使用不同的基础,并且每条指令都开始构建的新阶段。您可以选择性地将工件从一个阶段复制到另一个阶段,在最终图像中留下不需要的所有内容。
Java例子
FROM maven AS build
ADD ./pom.xml pom.xml
ADD ./src src/
RUN mvn clean package
FROM lizhenliang/tomcat
RUN rm -rf /usr/local/tomcat/webapps/ROOT
COPY --from=build target/*.war /usr/local/tomcat/webapps/ROOT.war
Golang例子
FROM golang:1.7.3
WORKDIR /go/src/github.com/alexellis/href-counter/
RUN go get -d -v golang.org/x/net/html
COPY app.go .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=0 /go/src/github.com/alexellis/href-counter/app .
CMD ["./app"]
有疑问加站长微信联系(非本文作者)