7.云原生之Docker容器Dockerfile镜像构建浅析与实践
转载自:https://www.bilibili.com/read/cv15220707/?from=readlist
Dockerfile 镜像构建浅析与实践
描述:Dockerfile是一个文本格式的配置文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。
用户可以使用Dockerfile快速创建自定义的镜像;通过它所支持的内部指令,以及使用它创建镜像的基本过程,Docker拥有"一点修改代替大量更新"的灵活之处;
- 文本化的镜像生成操作让其方便版本管理和自动化部署;
- 每条命令对应镜像的一层,细化操作后保证其可增量更新,复用镜像块减小镜像体积
总结为一点就是将每一层修改、安装、构建、操作命令都写入到一个脚本之中。
温馨提示: 一个镜像构建时不能超过 127 层,我们需要保证稳定的变化的命令至于上层保证了每层打包出来的 Layer 能够尽可能的复用,而不会徒增镜像的大小,影响后续拉取镜像的速度;
1.基本结构
Dockerfile分为四个部分:
- 基础镜像信息:FROM <image> 或者 FROM <image>:<tag>
- 维护者信息: MAINTAINER (建议使用LABEL标签进行替代,先已丢弃)
- 镜像标签信息: LABEL
- 镜像操作指令: RUN
- 容器启动时执行指令: CMD
例如:在/opt/目录中利用dockerfile创建一个基于ubuntu的nginx容器与mysql服务;
# Usage: docker build -t hub.weiyigeek.top/first_tag -f /opt/dockerfile .
#1.第一行必须指定基于的基础镜像
FROM ubuntu
#2.前期操作处理
MAINTAINER weiyigeek weiyigeek@qq.com #会影响实际仓库的拉取
LABEL version="1.0" #容器元信息,帮助信息,Metadata,类似于代码注释
LABEL maintainer="weiyigeek@163.com"
WORKDIR /opt/demo #切换工作空间(建议使用绝对路径)
ADD /opt/package /data/ # 把本地文件目录添加到镜像中
ENV MYSQL_VERSION 5.6 # 设置一个mysql常量 环境变量,尽可能使用ENV增加可维护性
#3.镜像的操作命令
#RUN指令时对镜像执行跟随的命令,每运行一条RUN指令,镜像添加新的一层并提交;
RUN echo "deb http://archive.ubuntu.com/ubuntu/ raring main uiverse" >> /etc/apt/source.list
RUN apt-het update && apt-get install -y nginx \
net-tools mysql-server="${MYSQL_VERSION}"
RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf
#4.镜像启动时候执行的命令
CMD /usr/sbin/nginx
在编写完成Dockerfile之后可以通过docker build 命令来创建镜像,该命令读取指定路径下(包括子目录)的dockerfile(实际上是构建上下文Context),并将该路径下的内容发送给Docker服务端由它创建镜像;
因此一般建议放置Dockerfile的目录为空另外可以通过dockerignore文件(每一行添加一条匹配模式)会让Docker忽略路径下的目录和文件;
docker 镜像生成常用命令:
docker build [选项]
- t :指定标签信息
--build-arg <参数名>=<值>
# 构建镜像的几种方式:
#1) 指定的Dockfile所在路径为/tmp/docker_builder
$docker build -t [TAG/version] /tmp/docker_builder
#2) 支持从 URL 构建
$docker build https://github.com/twang2218/gitlab-ce-zh.git#:11.1
#3) 用给定的 tar 压缩包构建
$docker build http://server/context.tar.gz
#4) 从标准输入中读取 Dockerfile 进行构建
$docker build - < Dockerfile
$cat Dockerfile | docker build -
#5) 从标准输入中读取上下文压缩包进行构建
$docker build - < context.tar.gz #标准输入的文件格式还可以是 gzip、bzip2 以及 xz
2.指令浅析
Dockerfile指令参数(Instruction arguments)如下,可以参考Docker官方有关dockerfile指令介绍的详细文档。
https://docs.docker.com/engine/reference/builder
完整解决Dockerfile
#当我们需要在一个镜像中操作添加更新然后打包放在子项目中,在以后的日子里都以此镜像来更新创建容器,为了方便版本控制所以引入了ONBUILD指令
FROM node:slim
RUN mkdir /app
WORKDIR /app
ONBUILD COPY ./package.json /app
ONBUILD RUN [ "npm", "install" ]
ONBUILD COPY . /app/
CMD [ "npm", "start" ]
#在构建基础镜像的时候 -t my-node,这三行ONBUILD并不会被执行,然后各个项目的 Dockerfile 就变成了简单地:
# 例如,执行docker build 并不会执行ONBUILD ,只有在使用my-node-onbuild:latest 作为基础镜像时才触发。
Docker build -t weiyigeek/my-node-onbuild:latest .
FROM my-node
#当在各个项目目录中,用这个只有一行的 Dockerfile 构建镜像时,之前基础镜像的那三行 ONBUILD 就会开始执行,成功的将当前项目的代码复制进镜像、并且针对本项目执行 npm install,生成应用镜像。
基础示例:
# Dockerfile 示例
# (1) 设置了每 5 秒检查一次(这里为了试验所以间隔非常短,实际应该相对较长),如果健康检查命令超过 3 秒没响应就视为失败
# 并且使用 curl -fs http://localhost/ || exit 1 作为健康检查命令。
FROM nginx
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
HEALTHCHECK --interval=5s --timeout=3s --retries=5 \
CMD curl -fs http://localhost/ || exit 1
# (2) 使用 docker build 来构建这个镜像并启动;
docker build -t myweb:v1 .
$ docker run -d --name web -p 80:80 myweb:v1
# (3) 最初的状态为 (health: starting)在等待几秒钟后,再次 docker container ls 就会看到健康状态变化为了 (healthy);
# 如果健康检查连续失败超过了重试次数,状态就会变为 (unhealthy)。
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
03e28eb00bd0 myweb:v1 "nginx -g 'daemon off" 18 seconds ago Up 16 seconds (healthy) 80/tcp, 443/tcp web
# (4) 健康检查命令的输出(包括 stdout 以及 stderr)都会被存储于健康状态里,可以用 docker inspect 来查看
$ docker inspect --format '{{json .State.Health}}' web | python -m json.tool
{
"FailingStreak": 0,
"Log": [
{
"End": "2019-12-30T14:35:37.940957051Z",
"ExitCode": 0,
"Output": "<!DOCTYPE html>\n<html>\n<head>\n<title>Welcome to nginx!</title>....",
"Start": "2019-12-30T14:35:37.780192565Z"
}
],
"Status": "healthy"
}
3.补充知识
4.基础实战