🍿 02-基于Dockerfile构建企业级生产环境镜像
相关官网地址
-
Docker 官网:https://docs.docker.com/
-
Docker GitHub:https://github.com/moby/moby
-
Docker Hub 镜像仓库:https://registry.hub.docker.com
-
DaoCloud 镜像加速器(拉取镜像慢时使用):https://dashboard.daocloud.io/mirror
一、Dockerfile 语法详解
1. 什么是 Dockerfile
Dockerfile 是构建镜像的文本指令文件,通过 docker build 命令读取文件内指令,自动完成镜像构建;可使用 -f 参数指定非默认名称的 Dockerfile 文件。
2. Dockerfile 构建流程
-
基于指定基础镜像启动临时容器
-
逐行执行文件中的指令,修改容器内容
-
提交修改,生成新镜像层
-
基于新镜像再次启动临时容器,执行下一条指令
-
循环执行,直至所有指令运行完毕
3. 常用指令全解
(1)FROM
作用:指定基础镜像,Dockerfile 第一条指令必须是 FROM,后续所有操作都基于该镜像。
FROM centos
(2)MAINTAINER
作用:标注镜像作者、联系方式等信息。
MAINTAINER ZHappy
(3)RUN
作用:构建镜像过程中执行命令(镜像构建阶段运行),分两种写法:
- Shell 模式(常用)
RUN echo hello
- Exec 模式
RUN ["/bin/bash","-c","echo hello"]
(4)EXPOSE
作用:声明容器对外暴露的端口,仅为标记,不会自动开启端口映射。
- 使用
docker run -P(大写 P)时,宿主机将随机映射该端口。
# 声明单个端口
EXPOSE 80
# 声明多个端口
EXPOSE 80 8080
(5)CMD
作用:容器启动时默认执行命令(容器运行阶段运行),docker run 后跟指令会覆盖 CMD 配置。
三种用法:
# Exec 模式(推荐)
CMD ["/usr/sbin/nginx","-g","daemon off;"]
# Shell 模式
CMD echo "start container"
# 作为 ENTRYPOINT 的默认参数
CMD ["param1","param2"]
示例
FROM centos
MAINTAINER ZHappy
RUN yum clean all
RUN yum install nginx -y
EXPOSE 80
CMD ["/usr/sbin/nginx","-g","daemon off;"]
构建 \& 运行:
# 构建镜像
docker build -t="dockerfile/test-cmd:v1" .
# 启动容器,无需重复写启动命令
docker run -p 80 --name cmd_test2 -d dockerfile/test-cmd:v1
(6)ENTRYPOINT
作用:指定容器启动入口命令,和 CMD 类似,但默认不会被 **docker run** 指令覆盖;仅使用 --entrypoint 参数时可强制覆盖。
- 可与
CMD搭配:ENTRYPOINT写固定命令,CMD充当动态参数。
基础用法
# Exec 模式
ENTRYPOINT ["nginx", "-c"]
# Shell 模式
ENTRYPOINT nginx -g daemon off;
组合用法示例
FROM nginx
ENTRYPOINT ["nginx", "-c"] # 固定指令
CMD ["/etc/nginx/nginx.conf"] # 默认参数
运行测试:
# 不传参,使用默认参数:nginx -c /etc/nginx/nginx.conf
docker run nginx:test
# 传参,替换默认参数:nginx -c /etc/nginx/new.conf
docker run nginx:test -c /etc/nginx/new.conf
(7)COPY
作用:从构建上下文目录复制文件 / 目录到容器内路径,仅做单纯复制,官方推荐日常文件复制使用。
- 目标路径不存在会自动创建;支持通配符;可指定文件属主。
# 基础写法
COPY index.html /usr/share/nginx/html/
# 带权限配置
COPY --chown=root:root test.txt /data/
# 通配符
COPY hom* /mydir/
(8)ADD
作用:功能包含 COPY,额外支持自动解压 gzip/bzip2/xz 格式压缩包。
-
缺点:不解压场景下无法单纯传输压缩包,容易破坏构建缓存。
-
选型建议:单纯复制用 COPY,需要解压用 ADD。
# 自动解压 tar 包到 /usr/local/
ADD apache-tomcat-8.0.26.tar.gz /usr/local/
(9)VOLUME
作用:定义匿名数据卷,用于持久化数据。
-
防止容器删除 / 重启导致数据丢失;避免容器磁盘持续膨胀。
-
容器运行时可通过
docker run -v手动挂载覆盖。
VOLUME ["/data", "/logs"]
(10)WORKDIR
作用:指定容器内工作目录,后续 RUN/COPY/CMD 等指令都会在该目录下执行。
- 目录会持久存在,建议使用绝对路径。
WORKDIR /usr/local/tomcat8
(11)ENV
作用:设置环境变量,构建和运行阶段均可引用。
# 定义变量
ENV NODE_VERSION 6.6.6
# 引用变量
RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz"
(12)USER
作用:切换后续指令执行的用户 / 用户组,前提是用户已存在。
USER nginx
USER nginx:nginx
(13)ONBUILD
作用:延迟执行指令(镜像触发器)。
- 当前镜像构建时不生效;当该镜像被其他镜像用作基础镜像时,自动触发执行。
演示示例
- 编写基础镜像 Dockerfile
FROM centos
MAINTAINER ZHappy
RUN yum install nginx -y
# 延迟指令
ONBUILD COPY index.html /usr/share/nginx/html/
EXPOSE 80
ENTRYPOINT ["/usr/sbin/nginx","-g","daemon off;"]
- 构建基础镜像
docker build -t="onbuild-nginx:v1" .
- 编写新 Dockerfile,基于上述镜像构建
FROM onbuild-nginx:v1
EXPOSE 80
ENTRYPOINT ["/usr/sbin/nginx","-g","daemon off;"]
- 构建新镜像,此时会自动执行
ONBUILD内的 COPY 指令
docker build -t="onbuild-nginx1" .
(14)LABEL
作用:为镜像添加元数据(标签),键值对格式,用于备注作者、版本、描述等。
LABEL org.opencontainers.image.authors="ZHappy"
LABEL version="v1" description="nginx image"
(15)HEALTHCHECK
作用:容器健康检查,定时检测容器内服务运行状态。
# 自定义命令检查健康状态
HEALTHCHECK CMD curl -f http://localhost/ || exit 1
# 屏蔽基础镜像自带的健康检查
HEALTHCHECK NONE
(16)ARG
作用:构建参数,仅在 docker build 构建过程中生效,镜像运行后失效。
- 可通过
--build-arg动态传参覆盖默认值。
# 定义参数,带默认值
ARG VERSION=v1
# 构建时动态修改参数
docker build --build-arg VERSION=v2 -t test:v1 .
二、实战 1:Dockerfile 构建 Nginx 镜像
1. 准备文件
新建目录并上传本地 YUM 源文件 Centos-vault-8.5.2111.repo
mkdir dockerfile && cd dockerfile/
2. 编写 Dockerfile
FROM centos
MAINTAINER ZHappy
# 替换YUM源
RUN rm -rf /etc/yum.repos.d/*
COPY Centos-vault-8.5.2111.repo /etc/yum.repos.d/
# 安装依赖与Nginx
RUN yum install wget -y
RUN yum install nginx -y
# 拷贝自定义页面
COPY index.html /usr/share/nginx/html/
# 声明端口
EXPOSE 80
# 容器启动自动运行Nginx
ENTRYPOINT ["/usr/sbin/nginx","-g","daemon off;"]
3. 编写自定义页面 index.html
<html>
<head>
<title>page added to dockerfile</title>
</head>
<body>
<h1>Hello ,My Name is ZHappy,My wechat is luckylucky421302 </h1>
</body>
</html>
4. 构建镜像
docker build -t="ZHappy/nginx:v1" .
# 查看镜像
docker images | grep nginx
5. 启动容器并测试访问
# 后台启动容器,随机映射80端口
docker run -d -p 80 --name html2 ZHappy/nginx:v1
# 查看容器端口
docker ps | grep html2
# 访问测试(替换为你的服务器IP+映射端口)
curl http://192.168.40.180:49154
三、实战 2:Dockerfile 构建 Tomcat 镜像
环境准备
新建目录,上传以下文件:
-
apache-tomcat-8.0.26.tar.gz(Tomcat 压缩包) -
jdk-8u45-linux-x64.rpm(JDK 安装包) -
Centos-vault-8.5.2111.repo(YUM 源文件)
mkdir tomcat8 && cd tomcat8
方式 1:基础版(需手动启动 Tomcat)
1. 编写 Dockerfile
FROM centos
MAINTAINER ZHappy
# 替换YUM源
RUN rm -rf /etc/yum.repos.d/*
COPY Centos-vault-8.5.2111.repo /etc/yum.repos.d/
RUN yum install wget -y
# 解压JDK、Tomcat
ADD jdk-8u45-linux-x64.rpm /usr/local/
ADD apache-tomcat-8.0.26.tar.gz /usr/local/
# 安装JDK、重命名Tomcat目录
RUN cd /usr/local && rpm -ivh jdk-8u45-linux-x64.rpm
RUN mv /usr/local/apache-tomcat-8.0.26 /usr/local/tomcat8
# 声明端口
EXPOSE 8080
2. 构建 \& 运行
# 构建镜像
docker build -t="tomcat8:v1" .
# 启动容器
docker run --name tomcat8 -itd -p 8080 tomcat8:v1
# 进入容器,手动启动Tomcat
docker exec -it tomcat8 /bin/bash
/usr/local/tomcat8/bin/startup.sh
方式 2:进阶版(容器启动自动运行 Tomcat)
1. 编写 Dockerfile1
FROM centos
MAINTAINER ZHappy
RUN rm -rf /etc/yum.repos.d/*
COPY Centos-vault-8.5.2111.repo /etc/yum.repos.d/
RUN yum install wget -y
ADD jdk-8u45-linux-x64.rpm /usr/local/
ADD apache-tomcat-8.0.26.tar.gz /usr/local/
RUN cd /usr/local && rpm -ivh jdk-8u45-linux-x64.rpm
RUN mv /usr/local/apache-tomcat-8.0.26 /usr/local/tomcat8
# 容器启动自动运行Tomcat并打印日志
ENTRYPOINT /usr/local/tomcat8/bin/startup.sh && tail -F /usr/local/tomcat8/logs/catalina.out
EXPOSE 8080
推荐写法:
ENTRYPOINT ["/usr/local/tomcat8/bin/catalina.sh", "run"]
2. 构建 \& 运行
# -f 指定Dockerfile文件名
docker build -f dockerfile1 -t="tomcat8:v2" .
# 启动容器
docker run --name tomcat68 -itd -p 8080 tomcat8:v2 /bin/bash
# 查看端口并访问
docker ps |grep tomcat68
四、扩展实战:Go 项目构建镜像
1. 环境准备(CentOS7.9)
# 安装Go环境
yum install go -y
# 创建项目目录
mkdir test && cd test
2. 编写 Go 代码 main.go
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func statusOKHandler(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"status": "success~welcome to study"})
}
func versionHandler(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"version": "v1.1版本"})
}
func main() {
router := gin.New()
router.Use(gin.Recovery())
router.GET("/", statusOKHandler)
router.GET("/version", versionHandler)
router.Run(":8080")
}
3. 编译二进制程序
# 初始化项目
go mod init test
# 配置国内代理
go env -w GOPROXY=https://goproxy.cn,direct
# 拉取依赖
go mod tidy
# 交叉编译 Linux 可执行文件
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o k8s-demo main.go
4. 编写 Dockerfile
# 轻量Alpine基础镜像
FROM alpine
# 工作目录
WORKDIR /data/app
# 拷贝可执行文件
ADD k8s-demo /data/app/
# 启动程序
CMD ["/bin/sh","-c","./k8s-demo"]
5. 构建镜像 \& 运行容器
docker build -t ZHappy/k8sdemo:v1 .
# 端口映射:宿主机30180 -> 容器8080
docker run -d --name go -p 30180:8080 ZHappy/k8sdemo:v1
访问:服务器IP:30180
五、扩展实战:Python 项目构建镜像
1. 准备代码
解压项目压缩包,进入项目目录(包含 main.py、requirements.txt)
tar zxvf hello-python.tar.gz
cd /root/hello-python/app
2. 编写 Dockerfile
# 基于Python3.7官方镜像
FROM python:3.7
# 创建目录并设置工作目录
RUN mkdir /app
WORKDIR /app
# 拷贝所有项目文件
ADD . /app/
# 升级pip、安装项目依赖
RUN /usr/local/bin/python -m pip install --upgrade pip
RUN pip install -r requirements.txt
# 声明端口
EXPOSE 5000
# 启动Python程序
CMD ["python","/app/main.py"]
3. 构建镜像 \& 运行容器
# 构建镜像
docker build -t hello-python:v1 .
# 启动容器,端口映射 30050:5000
docker run -d --name python -p 30050:5000 hello-python:v1
访问:服务器IP:30050