目录
三、Dockerfile 案例实施(构建 Nginx 容器)
编写 Dockerfile(/opt/nginx/Dockerfile):
编写启动脚本 run.sh(与 Dockerfile 同目录):
访问 Nginx(假设主机 IP 为 192.168.10.101,端口为 8083):
一、Docker 镜像管理
Docker 镜像既是 Docker 核心技术,也是应用发布的标准格式。完整的 Docker 镜像可支撑容器运行,容器内安装的服务若需迁移,需将环境及服务生成新镜像。本案例介绍 Docker 镜像创建方法。
1. Docker 镜像结构
镜像由多层构成,可通过 docker history
查看各层内容及大小,每层对应 Dockerfile 一条指令。镜像默认存储于 /var/lib/docker/<storage-driver>
目录,容器在镜像上层添加读写层:容器内文件改动仅写入读写层,删除容器则读写层及改动丢失。
核心特性:
- Dockerfile 每条指令创建新镜像层;
- 镜像层可缓存复用;
- 若指令、文件、构建变量变化,对应镜像层缓存失效,后续层缓存也失效;
- 镜像层不可变:某层添加文件后,下层删除仅隐藏文件,镜像仍包含该文件。
2. Dockerfile 介绍
Dockerfile 是 Docker 解释的脚本,由多条指令组成(每条对应 Linux 命令),定义镜像构建逻辑,解决命令依赖(类似 Makefile)。相比镜像 “黑盒”,Dockerfile 更透明,支持灵活扩展。
二、Dockerfile 语法基础
Dockerfile 是构建镜像的文本文件,包含以下常用指令:
1. 基础指令
指令 | 作用 | 示例 |
---|---|---|
FROM | 必选,指定基础镜像(新镜像基于此构建) | FROM ubuntu:20.04 |
MAINTAINER (已弃用) | 指定维护者信息,推荐用 LABEL 替代 | MAINTAINER John Doe <johndoe@example.com> |
LABEL | 添加元数据(如作者、版本、描述),便于镜像管理 | LABEL version="1.0" description="Sample" maintainer="John" |
2. 环境设置指令
指令 | 作用 | 示例 |
---|---|---|
ENV | 设置容器运行时的环境变量 | ENV MYSQL_ROOT_PASSWORD=password |
ARG | 定义构建时的参数(仅构建阶段有效,可通过 --build-arg 覆盖) | ARG VERSION=1.0 |
3. 文件操作指令
指令 | 作用 | 示例 |
---|---|---|
COPY | 复制本地文件 / 目录到镜像(仅支持本地路径) | COPY app.py /app/ |
ADD | 类似 COPY ,但支持远程 URL 下载和自动解压压缩包 | ADD http://example.com/file.tar.gz /app/ |
WORKDIR | 设置后续指令(RUN/CMD 等)的工作目录 | WORKDIR /app |
4. 执行命令指令
指令 | 作用 | 示例 |
---|---|---|
RUN | 构建镜像时执行命令(如安装依赖),支持多命令串联(&& ) | RUN apt-get update && apt-get install -y python3 |
CMD | 容器启动时的默认命令(Dockerfile 中仅最后一个生效,可被 docker run 覆盖) | CMD ["python3", "app.py"] |
ENTRYPOINT | 容器启动时的固定命令(docker run 后参数会作为其参数,不被覆盖) | ENTRYPOINT ["python3"] CMD ["app.py"] (组合实现 python3 test.py ) |
5. 网络和暴露端口指令
指令 | 作用 | 示例 |
---|---|---|
EXPOSE | 声明容器监听端口(仅为元数据,需通过 docker run -p 实际映射) | EXPOSE 8080 |
6. 容器挂载指令
指令 | 作用 | 示例 |
---|---|---|
VOLUME | 定义数据卷挂载点(持久化 / 共享数据) | VOLUME ["/app/data"] |
三、Dockerfile 案例实施(构建 Nginx 容器)
步骤 1:拉取基础镜像
docker pull centos:7
步骤 2:创建工作目录及文件
-
创建目录:
mkdir -p /opt/nginx
-
编写 Dockerfile(
/opt/nginx/Dockerfile
):FROM centos:7 MAINTAINER nginx project <123456@qq.com> # 可替换为 LABEL RUN yum -y update && yum -y install pcre-devel zlib-devel gcc gcc-c++ make RUN useradd -M -s /sbin/nologin nginx # 创建非登录用户 ADD nginx-1.12.0.tar.gz /usr/local/ # 假设本地有 nginx 安装包 WORKDIR /usr/local/nginx-1.12.0 RUN ./configure \ --prefix=/usr/local/nginx \ --user=nginx \ --group=nginx \ --with-http_stub_status_module && make && make install ENV PATH /usr/local/nginx/sbin:$PATH # 配置 Nginx 命令路径 ADD run.sh /run.sh # 复制启动脚本 RUN chmod 755 /run.sh # 赋予执行权限 EXPOSE 80 # 声明端口 CMD ["/run.sh"] # 启动命令
-
编写启动脚本
run.sh
(与 Dockerfile 同目录):#!/bin/bash /usr/local/nginx/sbin/nginx -g "daemon off;" # 前台运行 Nginx
步骤 3:构建镜像
确保 nginx-1.12.0.tar.gz
已上传至 /opt/nginx
,执行构建:
docker build -t mynginx .
步骤 4:启动容器(多种方式)
方式 1:简单启动(映射端口 8080→80)
[root@localhost nginx]# docker run -d -i --name nginx01 -p 8080:80 mynginx
# 注意:-t 会导致 run.sh 不执行,此处用 -i 交互模式
方式 2:挂载卷 + 执行脚本
[root@localhost nginx]# docker run -d -it -p 8081:80 --name nginx02 \
-v /www/html:/web \ # 主机 /www/html → 容器 /web
mynginx /bin/bash -c /run.sh # 显式执行启动脚本
方式 3:多卷挂载(配置文件 + 网页目录)
[root@localhost ~]# mkdir /nginx # 主机配置目录
[root@localhost ~]# cp /opt/nginx/nginx.conf /nginx # 复制自定义配置
[root@localhost nginx]# docker run -dit \
-p 8083:80 \
-v /www/html:/web \ # 网页数据卷
-v /nginx/nginx.conf:/usr/local/nginx/conf/nginx.conf \ # 配置文件挂载
--name nginx04 \
mynginx \
/bin/bash -c /run.sh
步骤 5:测试访问
-
写入测试页面:
echo "web test">/www/html/index.html
-
访问 Nginx(假设主机 IP 为
192.168.10.101
,端口为 8083):http://192.168.10.101:8083
关键说明
- 镜像构建:
docker build
需在 Dockerfile 所在目录执行,-t
指定镜像名称。 - 容器启动:
-d
后台运行,-p
端口映射,-v
数据卷挂载,--name
容器命名。 - 启动脚本:
run.sh
确保 Nginx 前台运行(否则容器会因守护进程退出而停止)。
2.案例 2-- 构建 Tomcat 容器
(1)创建工作目录
[root@localhost ~]# mkdir /opt/tomcat/
[root@localhost ~]# cd /opt/tomcat/
(2)创建 dockerfile 文件
[root@localhost tomcat]# vim dockerfile
FROM centos:7
ADD jdk-8u91-linux-x64.tar.gz /usr/local/
ENV JAVA_HOME /usr/local/jdk1.8.0_91
ENV JAVA_BIN /usr/local/jdk1.8.0_91
ENV JRE_HOME /usr/local/jdk1.8.0_91
ENV PATH $PATH:/usr/local/jdk1.8.0_91/bin:/usr/local/jdk1.8.0_91/jre/bin
ENV CLASSPATH /usr/local/jdk1.8.0_91/jre/bin:/usr/local/jdk1.8.0_91/lib:/usr/local/jdk1.8.0_91/jre/lib/charsets.jar
ADD apache-tomcat-8.5.16.tar.gz /
RUN mv /apache-tomcat-8.5.16 /usr/local/tomcat
EXPOSE 8080
ADD run.sh /run.sh
RUN chmod 775 /run.sh
CMD ["/run.sh"]
(3)创建启动脚本
[root@localhost tomcat]# vim run.sh
#!/bin/bash
/usr/local/tomcat/bin/startup.sh
tailf /run
备注:
tailf /run //让启动脚本始终运行
(4)用 dockerfile 生成镜像
[root@localhost tomcat]# docker build -t mytomcat .
(5)运行容器
[root@localhost tomcat]# docker run -d -i -p 8080:8080 --name tomcat01 mytomcat
(6)访问 tomcat 网站
http://192.168.10.101:8080
3:案例 3-- 构建 mysql 容器
(1)创建工作目录
[root@localhost ~]# mkdir /opt/mysql
(2)创建 dockerfile 文件
[root@localhost ~]# cd /opt/mysql/
[root@localhost mysql]# vim dockerfile
FROM centos:7
RUN rm -rf /etc/yum.repos.d/*
#ADD CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo
RUN curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo
RUN yum clean all
RUN yum -y install mariadb mariadb-server
RUN chown -R mysql:mysql /var/lib/mysql
ADD init.sh /init.sh
RUN chmod 775 /init.sh
RUN /init.sh
EXPOSE 3306
CMD ["mysqld_safe"]
(3)编写 mysql 初始化脚本
[root@localhost mysql]# vim init.sh
#!/bin/bash
mysql_install_db --user=mysql
sleep 3
mysqld_safe &
sleep 3
mysqladmin -u "root" password "123456"
mysql -uroot -p123456 -e "grant all privileges on *.* to 'root'@'%' identified by '123456';"
mysql -uroot -p123456 -e "grant all privileges on *.* to 'root'@'localhost' identified by '123456';"
mysql -uroot -p123456 -e "flush privileges;"
(4)生成镜像
[root@localhost mysql]# docker build -t mysql .
(5)创建容器
[root@localhost mysql]# docker run -id -p 3306:3306 mysql
[root@localhost mysql]# yum -y install mysql
[root@localhost mysql]# mysql -uroot -p123456 -h 192.168.10.101 -P 3306
4:案例 4-- 构建 php
(1)创建工作目录
[root@localhost ~]# mkdir /opt/php
[root@localhost ~]# cd /opt/php
(3)创建 dockerfile (yum 安装安装)
[root@localhost php]#vim dockerfile
FROM centos:7
MAINTAINER jacker
RUN rm -rf /etc/yum.repos.d/*
RUN curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo
RUN yum clean all
RUN yum install epel-release -y && yum install -y php php-fpm php-common php-mysqlnd
EXPOSE 9000
CMD ["php-fpm"]
(3)生成镜像
[root@localhost php]# docker build -t myphp .
(4)启动容器
[root@localhost php]# docker run -d -i -p 9000:9000 myphp /bin/bash
四:Dockerfile 语法注意事项
在编写 Dockerfile 时,掌握基础语法的注意事项能够帮助你构建出高效、可靠且易于维护的 Docker 镜像。以下是一些关键的注意事项:
1:指令书写规范
(1)大小写
Dockerfile 中的指令不区分大小写,但建议使用大写,以增强可读性。例如,使用 FROM、RUN 而非 from、run。
(2)顺序
指令的顺序非常重要,因为 Docker 会按顺序依次执行这些指令。合理安排指令顺序有助于提高构建效率和镜像的可维护性。例如,将不常变动的指令放在前面,充分利用 Docker 构建缓存机制。
(3)注释
可以使用 # 来添加注释,这有助于解释 Dockerfile 中各部分的作用,提高代码的可读性。
2:基础镜像选择
(1)稳定性与安全性
选择稳定、官方且维护良好的基础镜像,这样能保证镜像的安全性和可靠性。例如,官方的 ubuntu、alpine 等镜像都有较好的维护和更新机制。
(2)镜像大小
如果对镜像大小有严格要求,可选择轻量级的基础镜像,如 alpine 镜像,它体积小巧,适合构建资源占用少的容器。
3:文件操作注意
(1)COPY 与 ADD 的区别
- COPY 仅用于简单的文件和目录复制,语法清晰,性能较好,推荐优先使用。
- ADD 除复制功能外,还支持从 URL 下载文件和自动解压压缩文件,但功能复杂可能带来安全风险和不可预测性,所以仅在确实需要这些额外功能时使用。
(3)文件路径
使用相对路径时要确保路径在构建上下文中是正确的。构建上下文是指执行 docker build 命令时指定的目录,只有该目录下的文件和子目录才能被复制到镜像中。
4:执行命令要点
(1)RUN 命令优化
尽量将多个相关的命令合并成一个 RUN 指令,减少镜像的层数,从而减小镜像体积。例如,使用 && 连接多个命令
(2)清理临时文件和缓存
要及时清理临时文件和缓存,避免将不必要的文件包含在镜像中。如上述示例中使用 rm -rf /var/lib/apt/lists/* 清理 APT 缓存。
(3)CMD 与 ENTRYPOINT 搭配:
- CMD 为容器提供默认执行命令,ENTRYPOINT 配置容器启动时执行的命令。当两者搭配使用时,CMD 通常作为 ENTRYPOINT 的默认参数。
例如:
ENTRYPOINT ["python3"]
CMD ["app.py"]
- 若在 docker run 时指定了命令,CMD 的内容会被覆盖,而 ENTRYPOINT 的命令不会被覆盖,指定的命令会作为参数传递给 ENTRYPOINT。
5:环境变量和参数设置
(1)ENV 与 ARG 的区别:
- ENV 设置的环境变量在容器运行时持续存在,可被容器内的应用程序使用。
- ARG 定义的参数仅在镜像构建过程中有效,用于传递构建时的参数。
(2)安全性
避免在 ENV 或 ARG 中设置敏感信息(如密码、密钥等),若确实需要,可以在运行容器时通过环境变量传递。
(3)网络和端口声明
EXPOSE 指令:EXPOSE 只是声明容器监听的端口,不会进行实际的端口映射。在使用 docker run 启动容器时,需使用 -p 或 -P 选项进行端口映射。
6:缓存利用与清理
(1)缓存机制
Docker 构建镜像时会利用缓存,若某条指令的内容未发生变化,会直接使用之前的缓存结果,加快构建速度。因此,将不常变动的指令放在前面,可充分利用缓存。
(2)缓存清理
当需要强制重新构建镜像、不使用缓存时,可使用 docker build --no-cache 命令。