FROM
、RUN
、COPY
等,用于定义镜像构建步骤。docker build
时指定的路径(通常是 .
),包含构建所需的文件。FROM [:tag] [AS ] # 指定基础镜像(必须是第一条指令)
ARG [=] # 定义构建时变量(可在 build 命令中通过 --build-arg 覆盖)
COPY [--chown=:] ... # 复制文件/目录到镜像
ADD [--chown=:] ... # 类似 COPY,但支持远程 URL 和自动解压
WORKDIR # 设置工作目录(后续指令的相对路径基准)
ADD
支持解压 tar 文件和远程 URL,而 COPY
更简洁透明,推荐优先使用 COPY
。RUN # 执行 shell 命令(如安装软件)
RUN ["executable", "param1", "param2"] # exec 格式(避免 shell 解析)
RUN
命令创建一个新的镜像层,建议合并相关命令以减少层数(如 RUN apt-get update && apt-get install -y ...
)。ENV = ... # 设置环境变量(在容器运行时保持)
ENV PATH="/app/bin:$PATH" # 示例:添加路径到环境变量
CMD ["executable", "param1", "param2"] # 容器启动时执行的默认命令(可被 docker run 覆盖)
ENTRYPOINT ["executable", "param1", "param2"] # 容器启动时固定执行的命令(CMD 会作为参数附加)
组合使用
ENTRYPOINT ["python"]
CMD ["app.py"] # 最终命令:python app.py
EXPOSE [/...] # 声明容器运行时监听的端口(仅文档作用)
VOLUME ["/data"] # 声明挂载点(用于持久化数据)
USER [:] # 设置后续命令的执行用户
RUN mkdir /app && chown user:group /app # 创建目录并修改权限
每层的生成:每个 Dockerfile 指令(如 RUN
、COPY
)创建一个新的镜像层。
层的缓存:若某层的指令未变化,构建时会复用缓存,加速构建过程。
查看层:
docker history <image>
.
)下的所有文件发送给 Docker 引擎。.dockerignore
文件排除不需要的文件(如 .git
、node_modules
)。原理:使用多个 FROM
指令,每个指令定义一个构建阶段,可从前一阶段复制所需文件。
优势:大幅减小最终镜像体积(仅保留运行时必要文件)。
示例:
# 构建阶段
FROM maven:3.8.4 AS builder
COPY . /app
RUN mvn package
# 运行阶段
FROM openjdk:17-slim
COPY --from=builder /app/target/app.jar /app.jar
CMD ["java", "-jar", "/app.jar"]
alpine
、slim
版本)。RUN
命令,避免冗余文件(如清理包管理器缓存)。package.json
、requirements.txt
),再安装依赖,利用缓存。root
用户运行容器。:v1.0.0
而非 :latest
)。CMD
和 ENTRYPOINT
CMD
:提供默认参数,可被 docker run
覆盖。ENTRYPOINT
:设置固定命令,CMD
作为其参数。ADD
ADD
的远程 URL 和自动解压功能可能导致意外行为,优先使用 COPY
。.dockerignore
ARG ENV=production
RUN if [ "$ENV" = "development" ]; then apt-get install -y debug-tools; fi
docker buildx build --platform linux/amd64,linux/arm64 -t my-image .
HEALTHCHECK --interval=30s --timeout=3s \
CMD curl -f http://localhost/ || exit 1
GitLab CI/CD
build:
image: docker:latest
script:
- docker build -t my-image .
- docker push my-image
Jenkins
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'docker build -t my-image .'
}
}
}
}
创建一个目录将我们所需要的软件都方进入该目录中
nginx/
├── dockerfile # 构建 Nginx 镜像的脚本
├── nginx-1.19.5.tar.gz # Nginx 源码包
├── nginx.conf # Nginx 配置文件按需更改最后一行要添加daemon off
└── run.sh # 容器启动脚本
dockerfile内容
# 使用 CentOS 7 作为基础镜像
FROM centos:7
# 配置阿里云镜像源以加速软件下载
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 makecache
# 安装编译 Nginx 所需的工具和依赖库
RUN yum -y install gcc make pcre-devel openssl-devel zlib-devel
# 将本地的 Nginx 源码包添加到镜像中并解压到 /opt 目录
ADD nginx-1.19.5.tar.gz /opt
# 设置工作目录,后续命令将在此目录执行
WORKDIR /opt/nginx-1.19.5
# 配置并编译安装 Nginx 到 /usr/local/nginx 目录
RUN ./configure --prefix=/usr/local/nginx && make && make install
# 添加自定义的 Nginx 配置文件,覆盖默认配置
ADD nginx.conf /usr/local/nginx/conf/nginx.conf
# 声明容器运行时监听的端口(仅文档作用,实际映射需通过 docker run -p 参数)
EXPOSE 80
EXPOSE 443
# 添加启动脚本并赋予执行权限
ADD run.sh /run.sh
RUN chmod 755 /run.sh
# 设置容器启动时执行的命令,运行自定义启动脚本
CMD ["/run.sh"]
run.sh内容
#!/bin/bash
/usr/local/nginx/sbin/nginx
# 使用当前目录(.)的Dockerfile构建一个名为mynginx的Docker镜像
# -t 参数:指定镜像的标签(tag),格式为 [仓库名]:[标签名]
# 若省略标签名,默认为 latest
# . 表示构建上下文(build context),即Docker引擎获取构建文件的路径
docker build -t mynginx .
创建一个目录将我们所需要的软件都方进入该目录中
php/
├── dockerfile ###构建php的脚本
dockerfile内容
# 使用CentOS 7作为基础镜像
FROM centos:7
# 设置维护者信息
MAINTAINER dufu
# 删除默认的yum源配置
RUN rm -rf /etc/yum.repos.d/*
# 配置阿里云的CentOS 7基础源
RUN curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo
# 配置阿里云的EPEL扩展源
RUN curl -o /etc/yum.repos.d/epel.repo https://mirrors.aliyun.com/repo/epel-7.repo
# 清理yum缓存并重建缓存
RUN yum clean all
RUN yum makecache
# 安装常用工具和PHP相关组件
RUN yum -y install wget net-tools php php-fpm php-common php-devel php-mysql
# 修改php-fpm配置,监听所有IP地址
RUN sed -i 's/127.0.0.1/0.0.0.0/g' /etc/php-fpm.d/www.conf
# 注释掉允许访问的客户端限制
RUN sed -i 's/listen.allowed_clients/;listen.allowed_clients/g' /etc/php-fpm.d/www.conf
# 启用PHP默认字符集配置
RUN sed -i 's/;default_charset/default_charset/g' /etc/php.ini
# 声明容器运行时监听的端口
EXPOSE 9000
# 容器启动时执行的命令,启动php-fpm服务
CMD ["php-fpm"]
构建镜像
docker build -t myphp .
跟上面一样创建目录
mysql/ # MySQL 相关配置与脚本的存放目录
├── dockerfile # Docker 镜像构建文件(可选)
│ - 用于自定义 MySQL 镜像(如预装工具、修改配置等)
│ - 若未使用 `docker build` 构建镜像,此文件可能未生效
│ - 示例场景:添加额外依赖、修改默认配置路径等
│
├── init.sh # 初始化脚本(通常用于容器启动时执行预处理操作)
│ - 常见用途:
│ 1. 启动前创建数据库、用户或导入初始数据
│ 2. 修改 MySQL 配置参数(如调整 max_connections)
│ 3. 修复目录权限(如给 /var/lib/mysql 赋予正确权限)
│ - 使用方式:需在启动容器时通过 `--entrypoint` 或镜像构建时指定为入口脚本
│
└── my.cnf # MySQL 核心配置文件
- 用于覆盖容器内默认的 MySQL 配置(如端口、数据目录、字符集等)
- 需注意与 MySQL 版本兼容(避免使用 MariaDB 特有配置,如 [mysqld_safe])
- 启动容器时通过 `-v 路径 挂载生效
dockerfile内容
# 基于CentOS 7基础镜像构建(与其他服务保持一致的操作系统版本,确保兼容性)
FROM centos:7
# 删除系统默认的yum源配置文件(清除自带的官方源,避免下载速度慢)
RUN rm -rf /etc/yum.repos.d/*
# 配置阿里云的CentOS 7基础yum源(使用国内镜像源,加速依赖包下载)
RUN curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo
# 清理yum缓存(删除旧的缓存数据,避免干扰新源的使用)
RUN yum clean all
# 生成yum缓存(将新源的包信息提前缓存,加速后续安装步骤)
RUN yum makecache
# 安装MariaDB数据库及服务端(MariaDB是MySQL的开源分支,CentOS 7默认推荐版本)
RUN yum -y install mariadb mariadb-server
# 修改MySQL数据目录权限(将/var/lib/mysql目录及其子文件的所有者改为mysql用户和组,确保数据库进程有权限读写数据)
RUN chown -R mysql:mysql /var/lib/mysql
# 将当前目录的init.sh脚本添加到容器的根目录(init.sh是数据库初始化脚本,用于设置密码、授权等)
ADD init.sh /init.sh
# 给init.sh脚本添加可执行权限(755表示所有者有读写执行权限,组和其他用户有读和执行权限)
RUN chmod 755 /init.sh
# 执行初始化脚本(在镜像构建阶段运行init.sh,完成数据库初始化、密码设置、权限授权等操作)
RUN /init.sh
# 声明容器对外暴露的端口(MySQL默认端口为3306,用于外部或其他容器访问数据库)
EXPOSE 3306
# 容器启动时执行的命令(启动mysqld服务,以安全模式运行确保服务稳定)
# 注意:原命令可能存在笔误,正确应为"mysqld_safe"(少了一个d)
CMD ["mysqld_safe"]
init.sh 内容
#!/bin/bash
# 声明脚本解释器为 bash,确保脚本按 bash 语法执行
mysql_install_db --user=mysql
# 初始化 MySQL 数据库文件(适用于较旧的 MySQL 版本,如 5.6/5.7)
# --user=mysql:指定以 mysql 用户身份创建数据库文件(避免权限问题)
# 注意:MySQL 8.0+ 已弃用此命令,改用 mysqld --initialize 初始化
sleep 3
# 暂停 3 秒,等待数据库文件初始化完成(避免后续命令因初始化未完成而失败)
mysqld_safe &
# 以安全模式启动 MySQL 服务(后台运行,& 表示将进程放入后台)
# mysqld_safe 是 MySQL 的守护进程启动脚本,会自动重启崩溃的 mysqld 进程
# 注意:MySQL 8.0+ 推荐直接使用 mysqld 启动,此命令可能不兼容
sleep 3
# 暂停 3 秒,等待 MySQL 服务完全启动(确保后续命令能连接到数据库)
mysqladmin -u "root" password "123456"
# 为 root 用户设置初始密码(123456)
# mysqladmin 是 MySQL 管理工具,用于执行管理操作(如修改密码、关闭服务等)
# 注意:MySQL 8.0+ 初始密码存储在日志中,此命令可能失效,需改用 ALTER USER 语句
mysql -uroot -p123456 -e "grant all privileges on *.* to 'root'@'%' identified by '123456';"
# 允许 root 用户从任意主机(% 表示所有 IP)访问数据库,并授予所有权限
# -e:直接执行引号内的 SQL 命令(无需进入交互模式)
# 注意:MySQL 8.0+ 授权语法需分开设置权限和密码(先创建用户再授权)
mysql -uroot -p123456 -e "grant all privileges on *.* to 'root'@'localhost' identified by '123456';"
# 允许 root 用户从本地主机(localhost)访问数据库,并授予所有权限
# 补充本地访问权限,避免仅配置远程权限后本地无法登录
mysql -uroot -p123456 -e "flush privileges;"
# 刷新权限表,使上述授权配置立即生效(无需重启 MySQL 服务)
构建镜像
docker build -t mysql .
# 1. 创建自定义桥接网络(命名为 my_net)
# 作用:让多个容器在同一网络内可通过容器名互相访问(无需依赖 IP)
docker network create my_net
# 输出:d751e714da17f23d09bc168de7f388ee07449db9278b400f987233d269166855
# 说明:
# - 自定义网络解决了容器间通信问题(默认 bridge 网络需用 IP 访问,自定义网络支持容器名解析)
# - 后续启动的 php01、nginx01、mysql01 都加入此网络,可直接通过容器名(如 php01)互相访问
# 2. 启动 PHP 容器(命名为 php01),并加入 my_net 网络
docker run -id \
--net=my_net \ # 将容器加入 my_net 网络
-v /web:/web \ # 挂载宿主机的 /web 目录到容器内的 /web(共享网站文件,如 PHP 代码)
--name php01 \ # 给容器命名为 php01(方便网络访问和管理)
myphp # 使用的镜像名为 myphp(自定义的 PHP 镜像,需确保已构建)
# 输出:a8c424e31437ce35023d9da5c5c745794abad3514fd7c130d939a6148fab9776
# 说明:
# - -i:交互式模式(保持标准输入打开),-d:后台运行( detach 模式),合并为 -id
# - 容器内的 PHP-FPM 通常监听 9000 端口,供 Nginx 反向代理(对应 Nginx 配置中的 fastcgi_pass php01:9000)
# 3. 启动 Nginx 容器(命名为 nginx01),加入 my_net 网络并映射 80 端口
docker run -id \
--net=my_net \ # 加入 my_net 网络,可访问 php01 容器
-v /web:/web \ # 挂载宿主机 /web 目录(与 PHP 容器共享网站文件,确保 Nginx 和 PHP 访问的文件一致)
-v /root/nginx/nginx.conf:/usr/local/nginx/conf/nginx.conf \ # 挂载自定义 Nginx 配置文件(覆盖容器默认配置)
-p 80:80 \ # 端口映射:宿主机 80 端口 -> 容器内 80 端口(对外提供 HTTP 服务)
--name nginx01 \ # 容器命名为 nginx01
mynginx # 使用的镜像名为 mynginx(自定义的 Nginx 镜像,需确保已构建)
# 输出:22add0879a485aa3bf87efb2c3cd2392504a1c50622204c41f47ee60b74821b2
# 说明:
# - Nginx 容器通过挂载的配置文件,会将 .php 请求转发到 php01:9000(PHP-FPM)处理
# - 共享 /web 目录确保 Nginx 能读取 PHP 文件,且 PHP 解析时访问的文件路径一致
# 4. 启动 MySQL 容器(命名为 mysql01),加入 my_net 网络并映射 3306 端口
docker run \
-p 3306:3306 \ # 端口映射:宿主机 3306 端口 -> 容器内 3306 端口(对外提供 MySQL 服务)
--name mysql01 \ # 容器命名为 mysql01
-v /root/mysql/my.cnf:/etc/my.cnf \ # 挂载自定义 MySQL 配置文件(覆盖容器默认配置)
--net=my_net \ # 加入 my_net 网络,允许 PHP 容器通过 mysql01:3306 连接数据库
-d \ # 后台运行
mysql # 使用官方 MySQL 镜像(未指定版本时默认 latest,建议显式指定如 mysql:8.0)
# 输出:eb6a96f2f03c31fdcffaa11c3738ecc62a47e8be9df8fc78f14eddddad12d516
# 说明:
# - 需注意挂载的 my.cnf 配置需与 MySQL 镜像版本兼容(避免 MariaDB 特有配置,否则可能启动失败)
# - 首次启动建议添加 -e MYSQL_ROOT_PASSWORD=xxx 环境变量设置 root 密码(否则可能无法登录)
# - PHP 容器中的应用可通过主机名 mysql01 和端口 3306 连接数据库(如 PHP 代码中数据库主机填写 mysql01)
###在web目录有一个html的文件和两个php的文件我们分别访问这三个文件
[root@localhost web]# ls
test1.php test2.php index.html
###test1测试php test2 连接数据库 index.html 自己处理nginx本身处理
[root@localhost ~]# curl 192.168.10.101:80
adasd
[root@localhost ~]# curl -I 192.168.10.101:80/test1.php
HTTP/1.1 200 OK
Server: nginx/1.19.5
Date: Thu, 10 Jul 2025 18:11:35 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
X-Powered-By: PHP/5.4.16
[root@localhost ~]# curl 192.168.10.101:80/test2.php
test OK