摘要:正确的做法是直接执行可执行文件,并且要求以前台形式运行。官方镜像官方镜像在这里先定义了环境变量,其后的这层里,多次使用来进行操作定制。只有当以当前镜像为基础镜像,去构建下一级镜像的时候才会被执行。
基础命令
名称 | 作用 | 示例 |
---|---|---|
docker systen df | 查看镜像、容器、数据卷所占的空间 | |
docker images -q | 产生指定范围的id列表 | docker image ls -q redis |
docker image rm $() | 批量删除指定镜像 | docker image rm $(docker image ls -q redis) |
docker run | 基于镜像启动容器 | docker run --name webserver -d -p 80:80 nginx |
docker exec | 进入容器 | docker exec -it webserver /bin/bash |
docker diff | 查看容器存储层的改动 | docker diff webserver |
docker commit | 将容器的存储层保存为镜像 | docker commit [选项] <容器ID或容器名> [<仓库名>[:<标签>]] |
docker history | 具体查看镜像历史 | docker history nginx:v2 |
docker export | 导出本地容器 | docker export c422162c86da >mysql.tar |
docker import | 导入容器快照到本地镜像仓库 | cat mysql.tar | docker import - test/mysql:v1.0 |
docker save | 保存镜像(推荐Docker Registry方式) | docker save docker.io/mysql | gzip > mysql-test.tar.gz |
docker load | 加载镜像(推荐Docker Registry方式) | docker load -i mysql-test.tar.gz |
名称 | 作用 | 示例 |
---|---|---|
FROM | 指定基础镜像 | FROM scratch 指定一个空白的镜像 |
RUN | 用来执行命令行命令的 | RUN ["可执行文件", "参数1", "参数2"] |
COPY | 从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置 | COPY <源路径>... <目标路径> |
ADD | 更高级的复制文件 | (几乎不用它)所有复制文件用COPY,仅在需要自动解压缩的场合使用 ADD |
CMD | 容器启动命令 | 推荐使用 exec 格式 CMD ["可执行文件", "参数1", "参数2"...] 注意是双引号 |
ENTRYPOINT | 入口点 | 1 让镜像变成像命令一样使用; 2 应用运行前的准备工作 |
ENV | 设置环境变量 | ENV |
ARG | 构建参数 | ARG <参数名>[=<默认值>] |
VOLUME | 定义匿名卷 | VOLUME ["<路径1>", "<路径2>"...] |
EXPOSE | 声明运行时容器提供服务端口 | EXPOSE <端口1> [<端口2>...] |
WORKDIR | 指定工作目录 | WORKDIR <工作目录路径> |
USER | 指定当前用户 | USER <用户名> |
HEALTHCHECK | 健康检查 | HEALTHCHECK [选项] CMD <命令> :设置检查容器健康状况的命令 |
ONBUILD | 为他人做嫁衣 | ONBUILD <其它指令> |
介绍
Dockerfile 是一个文本文件,里面包含了一条条的指令,每一条指令构建一层,因此每一条指令的内容都是描述该层如何构建。
使用dockerfile的好处
避免了docker commit方式带来的臃肿,实际应用中不应采用docker commit.
基本流程
mkdir mynginx cd mynginx touch Dockerfile vim Dockerfile,写入 FROM nginx RUN echo "正确构建Hello, Docker!
" > /usr/share/nginx/html/index.html 构建镜像 docker build -t nginx:v3 . # 注意最后面有一个点 or docker build - < Dockerfile #从标准输入中读取 Dockerfile 进行构建 or cat Dockerfile | docker build - or docker build http://server/context.tar.gz #用给定的 tar 压缩包构建 or docker build https://github.com/twang2218/gitlab-ce-zh.git#:8.14 # 直接用 Git repo 进行构建 or docker build - < context.tar.gz # 从标准输入中读取上下文压缩包进行构建
Dockerfile 中每一个指令都会建立一层, RUN 也不例外。每一个 RUN 的行为, 就和刚才我们手工建立镜像的过程一样:新建立一层,在其上执行这些命令,执行结束 后, commit 这一层的修改,构成新的镜像。错误的示例
FROM debian:jessie RUN apt-get update RUN apt-get install -y gcc libc6-dev make RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz" RUN mkdir -p /usr/src/redis RUN tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 RUN make -C /usr/src/redis RUN make -C /usr/src/redis install正确的写法
FROM debian:jessie RUN buildDeps="gcc libc6-dev make" && apt-get update && apt-get install -y $buildDeps && wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz" && mkdir -p /usr/src/redis && tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 && make -C /usr/src/redis && make -C /usr/src/redis install && rm -rf /var/lib/apt/lists/* && rm redis.tar.gz && rm -r /usr/src/redis && apt-get purge -y --auto-remove $buildDeps关于上下文
COPY ./package.json /app/ 这并不是要复制执行 docker build 命令所在的目录下的 package.json ,也不是复制 Dockerfile 所在目录下的 package.json ,而是复制 上下文(context) 目录下的 package.jsonADD
FROM scratch ADD ubuntu-xenial-core-cloudimg-amd64-root.tar.gz / ...CMD
shell格式: CMD echo $HOME 实际执行: CMD [ "sh", "-c", "echo $HOME" ] Docker 不是虚拟机,容器中的应用都应该以前台执行,而不是像虚拟机、物理机里面那样, 用 upstart/systemd 去启动后台服务,容器内没有后台服务的概念。 CMD service nginx start 这个命令会被理解为 CMD [ "sh", "-c", "service nginx start"] ,因此主进程实际上是 sh 。 那么当 service nginx start 命令结束后, sh 也就结束了, sh 作为主进程退出了,自然就会令容器退出。 正确的做法是直接执行 nginx 可执行文件,并且要求以前台形式运行。比如: CMD ["nginx", "-g", "daemon off;"]ENTRYPOINT
场景一:让镜像变成像命令一样使用
错误的示范
FROM ubuntu:16.04 RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* CMD [ "curl", "-s", "http://ip.cn" ] docker build -t myip . docker run myip docker run myip -i # 如果加上-i参数,就会报错
正确的示范
FROM ubuntu:16.04 RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* ENTRYPOINT [ "curl", "-s", "http://ip.cn" ]
场景二:应用运行前的准备工作
启动容器就是启动主进程,但有些时候,启动主进程前,需要一些准备工作。 官方redis镜像 FROM alpine:3.4 ... RUN addgroup -S redis && adduser -S -G redis redis ... ENTRYPOINT ["docker-entrypoint.sh"] EXPOSE 6379 CMD [ "redis-server" ]
docker-entrypoint.sh #!/bin/sh ... # allow the container to be started with `--user` if [ "$1" = "redis-server" -a "$(id -u)" = "0" ]; then chown -R redis . exec su-exec redis "$0" "$@" fi exec "$@"ENV
官方node镜像 ENV NODE_VERSION 7.2.0 RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.ta r.xz" && curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc" && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc && grep " node-v$NODE_VERSION-linux-x64.tar.xz$" SHASUMS256.txt | sha256sum -c - && tar -xJf "node-v$NODE_VERSION-linux-x64.tar.xz" -C /usr/local --strip-components= 1 && rm "node-v$NODE_VERSION-linux-x64.tar.xz" SHASUMS256.txt.asc SHASUMS256.txt && ln -s /usr/local/bin/node /usr/local/bin/nodejs 在这里先定义了环境变量 NODE_VERSION ,其后的 RUN 这层里,多次使用 $NODE_VERSION 来进行操作定制。 可以看到,将来升级镜像构建版本的时候,只需要更新 7.2.0 即可, Dockerfile 构建维护变得更轻松了。 下列指令可以支持环境变量展开: ADD 、 COPY 、 ENV 、 EXPOSE 、 LABEL 、 USER 、 WORKDIR 、 VOLUME 、 STOPSIGNAL 、 ONBUILD 。ARG
Dockerfile 中的 ARG 指令是定义参数名称,以及定义其默认值。该默认值可以在构建命令 docker build 中用 --build-arg <参数名>=<值> 来覆盖。VOLUME
VOLUME /data 这里的 /data 目录就会在运行时自动挂载为匿名卷,任何向 /data 中写入的信息都不会记录进容器存储层, 从而保证了容器存储层的无状态化。当然,运行时可以覆盖这个挂载设置。 docker run -d -v mydata:/data xxxx 在这行命令中,就使用了 mydata 这个命名卷挂载到了 /data 这个位置,替代了Dockerfile 中定义的匿名卷的挂载配置。EXPOSE
要将 EXPOSE 和在运行时使用 -p <宿主端口>:<容器端口> 区分开来。 -p ,是映射宿主端口和 容器端口,换句话说,就是将容器的对应端口服务公开给外界访问,而 EXPOSE 仅仅是声明 容器打算使用什么端口而已,并不会自动在宿主进行端口映射WORKDIR
错误的示例
初学者常犯的错误是把 Dockerfile 等同于 Shell 脚本来书写 RUN cd /app RUN echo "hello" > world.txt 如果需要改变以后各层的工作目录的位置,那么应该使用 WORKDIR 指令USER
USER 指令和 WORKDIR 相似,都是改变环境状态并影响以后的层,用户需提前建好. RUN groupadd -r redis && useradd -r -g redis redis USER redis RUN [ "redis-server" ]HEALTHCHECK
FROM nginx RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* HEALTHCHECK --interval=5s --timeout=3s CMD curl -fs http://localhost/ || exit 1 这里我们设置了每 5 秒检查一次(这里为了试验所以间隔非常短,实际应该相对较长),如 果健康检查命令超过 3 秒没响应就视为失败,并且使用 curl -fs http://localhost/ || exit 1 作为健康检查命令。 查看 docker inspect --format "{{json .State.Health}}" web | python -m json.toolONBUILD
ONBUILD 是一个特殊的指令,它后面跟的是其它指令,比如 RUN , COPY 等,而这些指令, 在当前镜像构建时并不会被执行。只有当以当前镜像为基础镜像,去构建下一级镜像的时候才会被执行。 Dockerfile 中的其它指令都是为了定制当前镜像而准备的,唯有 ONBUILD 是为了帮助别人定制自己而准备的。
假设一个node.js的dockerfile如下
FROM node:slim RUN mkdir /app WORKDIR /app COPY ./package.json /app RUN [ "npm", "install" ] COPY . /app/ CMD [ "npm", "start" ]
现在有其他的镜像依赖这个镜像,假设基础镜像叫my-node
FROM node:slim RUN mkdir /app WORKDIR /app CMD [ "npm", "start" ]
那么其他依赖的子项目的镜像为
FROM my-node COPY ./package.json /app RUN [ "npm", "install" ] COPY . /app/ 基础镜像变化后,各个项目都用这个 Dockerfile 重新构建镜像,会继承基础镜像的更新 但是问题只解决了一半,如果这个子Dockerfile 里面有些东西需要调整呢? 比如 npm install 都需要加一些参数,那怎么办?这一行 RUN 是不可能放入基础镜像的, 因为涉及到了当前项目的 ./package.json ,难道又要一个个修改么? 所以说,这样制作基础镜像,只解决了原来的 Dockerfile 的前4条指令的变化问题, 而后面三条指令的变化则完全没办法处理。
用ONBUILD重写基础镜像
FROM node:slim RUN mkdir /app WORKDIR /app ONBUILD COPY ./package.json /app ONBUILD RUN [ "npm", "install" ] ONBUILD COPY . /app/ CMD [ "npm", "start" ] 在用ONBUILD构建基础镜像的时候,这三行并不会被执行
那么子镜像只需
FROM my-node 当在各个项目目录中,用这个只有一行的 Dockerfile 构建镜像时,之前基础镜像的那三行 ONBUILD 就会开始执行, 成功的将当前项目的代码复制进镜像、并且针对本项目执行 npm install ,生成应用镜像参考文档
Docker 从入门到实践
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/27405.html
摘要:导读要从容器化开始,而容器又需要从开始,本文将介绍如何写出一个优雅的文件。只要记住以上三点就能写出不错的。执行完成项目的构建。 导读 Kubernetes要从容器化开始,而容器又需要从Dockerfile开始,本文将介绍如何写出一个优雅的Dockerfile文件。 文章主要内容包括: Docker容器 Dockerfile 使用多阶构建 感谢公司提供大量机器资源及时间让我们可以实践...
摘要:用于配置当前所创建的镜像作为其它新创建镜像的基础镜像时,所执行的操作指令。运行构建命令构建命令用于使用创建镜像。 本文旨在用通俗的语言讲述枯燥的知识 前面讲到镜像的构建时,讲述的是用commit的方式构建镜像,而Dockerfile是另一种构建镜像的方式。 Dockerfile构建镜像是以基础镜像为基础的,Dockerfile是一个文本文件,内容是用户编写的一些docker指令,每一条...
摘要:我们可以了解到,镜像的定制实际上就是定制每一层所添加的配置文件。指令之指令的目的就是来指定基础镜像。指令之指令是用来执行命令行命令的。由于命令行的强大能力,指令在定制镜像时是最常用的指令之一。构建镜像这里我们使用了命令进行镜像构建。 我们可以了解到,镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜...
摘要:本文已获得原作者授权。在构建镜像的过程中会缓存一系列中间镜像。镜像时,会顺序执行中的指令,并同时比较当前指令和其基础镜像的所有子镜像,若发现有一个子镜像也是由相同的指令生成,则命中缓存,同时可以直接使用该子镜像而避免再去重新生成了。 本文已获得原作者 CodeSheep 授权。 概述 Dockerfile 是专门用来进行自动化构建镜像的编排文件(就像 Jenkins 2.0时代的 J...
摘要:前言自动化构建是应用发布过程中必不可少的环节,常用的构建工具有等。当然,我推荐个人体验的话就用官方的吧,因为这样你构建的镜像还可以与他人共享。 前言 自动化构建是应用发布过程中必不可少的环节, 常用的构建工具有jenkins ,walle 等。而这些工具在构建应用时通常会有以下问题: 需要直接或间接的写一坨用于构建的shell命令等,不易管理、兼容性较差 上面一点可能还比较容易解决,...
摘要:但是看了下,里面的软件源还是官方的,而且没有安装,所以就打算自己写一个,用它来构建适合自己的基础镜像。我事先配置好的,都是些基础的配置。添加的文件必须以构建上下文为根目录来找,不能超出构建上下文的范围。 我们可以从Docker Hub上下载官方仓库中的镜像,我自己就下载了ubuntu镜像,只有188M左右,很小巧了。但是看了下,里面的软件源还是官方的,而且没有安装vim,所以就打...
阅读 3296·2021-11-24 09:39
阅读 2803·2021-10-12 10:20
阅读 1903·2019-08-30 15:53
阅读 3075·2019-08-30 14:14
阅读 2599·2019-08-29 15:36
阅读 1119·2019-08-29 14:11
阅读 1954·2019-08-26 13:51
阅读 3406·2019-08-26 13:23