适合课堂 / 自学整理,结构:Docker 基础 → 安装 → 核心概念 → 常用命令 → Dockerfile 镜像构建 → Nginx 中文乱码实战(我们前面实操内容)

一、什么是 Docker

1. 传统虚拟机 和 Docker 容器区别

  • 虚拟机:完整虚拟一套硬件 + 独立完整操作系统,体积大、启动慢、资源占用高
  • Docker(容器)共享宿主机 Linux 内核,只打包程序、依赖、配置,没有独立内核;体积小、秒级启动、资源消耗极低

一句话:虚拟机是 “装完整电脑”,Docker 是 “打包程序运行环境”

2. Docker 核心作用

一次打包,到处运行 开发、测试、生产环境统一,解决经典问题:“我本地能跑,线上不行”

3. Docker 三大核心组件(必考)

  1. 镜像(Image):只读静态模板(相当于安装包),包含程序、依赖、配置。镜像不能修改,分层存储。
  2. 容器(Container):镜像运行出来的实例,有一层可读写临时层;程序实际跑在容器里。删除容器,容器内手动修改的内容默认丢失。
  3. 仓库(Registry):存放镜像的地方,官方公共仓库:Docker Hub

类比理解:镜像 = 蛋糕配方,容器 = 按照配方烤出来的蛋糕实例

二、Docker 安装部署(CentOS 系统,我们实操环境)

环境:CentOS7 / CentOS Stream

1. 前置:卸载旧版本 docker(可选)

yum remove -y docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine

2. 安装 yum 工具包

yum install -y yum-utils

3. 设置 docker yum 源(国内推荐阿里云源,速度快)

yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

4. 安装 Docker 引擎(ce = 社区免费版)

yum install -y docker-ce docker-ce-cli containerd.io

5. 启动 Docker & 设置开机自启

# 启动
systemctl start docker
# 开机自动启动
systemctl enable docker

6. 验证是否安装成功

docker --version
docker info
# 运行hello-world测试
docker run hello-world


解释:
Unable to find image 'hello-world:latest' locally
# 本地电脑(宿主机)找不到 hello-world:latest 这个镜像
latest: Pulling from library/hello-world
4f55086f7dd0: Pull complete
# 去 Docker Hub 公共仓库拉取 hello-world 镜像,下载完成
Digest: sha256:5dd0d3e6e255913fc30f90b9f2b1d359cc2cbdb48090cc4b65f1676e203243cc
# 镜像的唯一校验值(哈希值,用来确认镜像没被篡改)
Status: Downloaded newer image for hello-world:latest
# 状态:已经下载好了最新版 hello-world 镜像
Hello from Docker!
This message shows that your installation appears to be working correctly.
# 来自Docker的问候!这条信息代表你的Docker安装正常,可以使用。

✅ 优化配置:国内镜像加速(必配,否则拉镜像很慢)

# 创建daemon.json配置文件
cat > /etc/docker/daemon.json <<EOF
{
  "registry-mirrors": ["https://mirror.baidubce.com"]
}
EOF
# 重启docker生效
systemctl daemon-reload
systemctl restart docker

三、Docker 基础常用命令(分类整理)

1. 镜像相关

# 搜索镜像
docker search nginx
# 拉取镜像(不加tag默认latest最新版)
docker pull nginx:1.27
# 查看本地镜像
docker images
# 删除镜像(镜像id/名字)
docker rmi 镜像ID

2. 容器相关(高频)

# 创建并启动容器
# -d 后台运行  --name 自定义名字 -p 宿主机端口:容器内端口  镜像名:tag
docker run -d --name nginx-test -p 8080:80 nginx:1.27

# 查看正在运行容器
docker ps
# 查看所有容器(包含停止的)
docker ps -a

# 停止容器
docker stop 容器名/容器ID
# 启动已存在的容器
docker start 容器名/容器ID
# 删除容器(必须先停止,加-f强制删除正在运行的)
docker rm -f 容器名/容器ID

# 进入正在运行的容器内部
docker exec -it 容器名 /bin/bash

# 宿主机 和 容器之间 文件互传
# 宿主机文件 → 容器
docker cp 本地文件 容器名:容器内路径
# 容器文件 → 宿主机
docker cp 容器名:容器内路径 本地路径

做端口映射的时候要用如果是在linux虚拟机上要用内网IP,如果是云服务器的话就用公网IP(云服务器本身自带独立公网 IP,这里的公网 IP,不是 Docker 单独的 IP,是这台服务器整机的公网 IP,Docker 只是把本机 80 端口转发到容器内部),这样就可以在浏览器打开你的docker了。

3. 其他辅助

# 查看容器日志
docker logs 容器名

四、Dockerfile 构建自定义镜像(重点,本次 Nginx 实战核心)

需求:不直接用官方原始 nginx 镜像,自己定制环境、文件,打包成新镜像 ✅ 核心规则:Dockerfile 里每一条指令都会生成镜像分层,镜像只读固化

常用 Dockerfile 指令

表格

指令作用
FROM基础镜像,必须第一行
ENV设置环境变量
COPY把宿主机文件复制进镜像内
RUN构建镜像时执行命令
EXPOSE声明容器要开放的端口(仅声明,不实际开放)
CMD容器启动默认执行命令

nginx:1.27 镜像是 Debian 基础镜像,容器内默认字符集是 POSIX(不是 UTF-8),Shell 不识别中文,直接把中文转成八进制编码 \345\260\232...,最终网页渲染出现乱码 / 繁体异常。

✅ 我们实战最终 Dockerfile(v2 版本,固化 utf8 环境 + 带 meta 的 html)

FROM nginx:1.27
# 系统级UTF8编码,固化在镜像,不会被echo修改
ENV LANG=C.UTF-8
ENV LC_ALL=C.UTF-8
# 将本地写好的完整html打包进镜像
COPY index.html /usr/share/nginx/html/index.html
# 声明端口
EXPOSE 80

✅ 构建镜像命令

# -t 镜像名:版本号  . 代表当前目录找Dockerfile
docker build -t mynginx-dockerfile:v2 .

五、文件重定向符号(本次踩坑重点)

表格

符号含义风险
>覆盖写入清空原有全部内容,再写入新内容❗ 本次乱码根源
>>追加写入保留原有内容,新内容加到末尾 ✅
# 覆盖(危险,会删掉meta标签)
echo "<h1>测试文字</h1>" > index.html
# 追加(安全)
echo "<p>新增一行</p>" >> index.html
# 多行写入完整html
cat > index.html <<EOF
完整html代码
EOF

六、Nginx 中文乱码实战复盘(我们前面完整踩坑 + 解决,重点)

两个独立 UTF-8 配置(极易混淆)

  1. ENV LANG=C.UTF-8(系统编码) 作用:Linux 底层存储中文不乱码,固化在镜像,echo 修改不了 缺陷:不会通知浏览器编码格式
  2. <meta charset="utf-8">(html 内标签) 作用:告诉浏览器使用 utf8 解析页面 本质:只是 html 里一段文本,一旦>覆盖文件直接消失 → 浏览器乱码

现象复现流程

  1. 基于 v2 镜像启动容器,index.html 自带 meta 标签,中文正常
  2. 进入容器执行 echo "<h1>测试</h1>" > index.html
  3. index.html 原有全部代码清空,meta 标签消失 → 网页乱码
  4. 重点:系统编码依旧是 UTF8,文字本身没问题,只是缺少网页编码声明
  5. 解决方案:想要永久保留完整 html,必须写入 Dockerfile 重新 build 镜像,而不是容器内手动修改

关键结论

容器内直接修改文件 = 临时生效,删除容器就丢失 想要永久固化配置 / 文件 → Dockerfile + docker build 打包镜像

七、拓展方案(可选笔记)

方案 1:安全修改页面(追加内容,不破坏 html 结构)

echo "<p>新增文字</p>" >> /usr/share/nginx/html/index.html

方案 2:生产级 Nginx 全局 utf8(nginx 响应头强制编码,不需要 meta 标签)

FROM nginx:1.27
ENV LANG=C.UTF-8
ENV LC_ALL=C.UTF-8
RUN echo 'charset utf-8;' >> /etc/nginx/conf.d/default.conf
COPY index.html /usr/share/nginx/html/index.html
EXPOSE 80

八、一句话速记总结(背诵版)

  1. Docker 共享宿主机内核,轻量、秒启动,核心:镜像、容器、仓库
  2. Dockerfile 构建镜像,镜像只读固化;容器可读写临时层,容器内修改默认不持久
  3. >覆盖清空文件,>>追加内容
  4. ENV C.UTF-8管系统存储文字,meta charset管浏览器解析网页
  5. 永久修改环境 / 文件 → build 镜像;临时调试 → 直接改运行容器

九、保存镜像

1、可以把镜像打包发给别人使用

保存也加载(load)输出别人发给我们的镜像之后,我让他继续运行run运行后,给他设置名字,以及端口映射

然后区去浏览器看下 ,是不是和别人发我们镜像页面一样,一样的就成功啦

十、镜像分享到社区

Docker Hub 就是 Docker 官方公共社区,别人可以直接 docker pull 下载你的镜像Docker

前置准备

  1. 浏览器打开 https://hub.docker.com 注册账号,记住你的Docker Hub 用户名(全部小写)
  2. 网页上点 Create repository 创建仓库,仓库名小写,选择 Public(公开)

仓库名字建议:mynginx,和本地镜像对应。

完整 4 步命令实操

①给本地镜像打 tag(最重要!)

格式:docker tag 本地镜像:版本 你的hub用户名/仓库名:版本

示例:假设你的 docker hub 用户名是 atguigudemo

# 本地镜像 mynginx:v1 → 改成符合hub规范名字
docker tag mynginx:v1 atguigudemo/mynginx:v1

⚠️坑:必须带上你的用户名,不能直接写 mynginx:v1 push,会报错。

打完 tag 查看:

docker images | grep hub里的用户名

②服务器命令行登录 Docker Hub

docker login

输入你的 DockerHub 用户名;

密码现在推荐用网页生成的Access Token,不要用账号原始密码登录。 登录成功提示:Login Succeeded

③push 推送上传到社区仓库

docker push 用户名/mynginx:v1

Docker 会分层上传镜像,全部层上传完成,网页 Docker Hub 仓库就能看到你的镜像。

可以在你的镜像这里添加说明书:

显示发布的版本和最新版本

④别人任意机器直接下载使用(分享完成)

其他人不需要 tar 包,一条命令拉取:

docker pull atguigudemo/mynginx:v1
docker run -d -p 8082:80 atguigudemo/mynginx:v1

📝笔记:两套分享方式对比

表格

分享方式命令特点
离线分享save‑load生成 tar 文件,拷贝文件给别人,不能网络 pull
社区公开分享 (Docker Hub)tag → login → push上传公共仓库,全世界可以 pull 下载

完整标准工作流(无 commit) Dockerfile → docker build → docker tag → docker push

高频踩坑

  1. ❌直接 push mynginx:v1 报错:denied: requested access to the resource is denied

原因:镜像名字缺少你的 hub 用户名命名空间,必须 docker tag 重命名。

  1. 镜像名全部小写,不能大写字母,Docker Hub 强制要求。
  2. latest标签坑:尽量用明确版本号 v1,不要无脑用 latest,版本会混乱。
  3. 国内服务器访问 Docker Hub 网络慢 / 推不上去:需要配置 docker 镜像加速器。

退出登录(可选)

docker logout

两套分享总结

  1. 内网 / 不能上网环境:用 docker save‑load tar 包
  2. 对外分享给所有人:Docker Hub tag + push

常用命令:

注:如果是云服务器的话,允许哪些端口访问是要在服务器上设置的;

两层防护
第一层:云厂商安全组(阿里云 / 腾讯云… 网页控制台配置)
⚠️这个不在 Linux 命令里面操作!网页后台设置
云服务器外面还有一层防火墙,叫安全组。
就算你 Linux 系统 firewalld 关了,如果安全组没放行端口,外网依旧访问不了。
举例:
你容器 -p 8082:80,宿主机用 8082 端口
👉安全组入方向规则,需要放行 8082 端口,允许来源 0.0.0.0/0(所有 IP)
如果你用 -p 80:80,就要放行 80 端口。
坑:只改 Linux 内部防火墙,忘记云平台安全组,浏览器访问超时。


第二层:Linux 系统内部防火墙 firewalld(服务器命令行操作)
CentOS7/8 默认开启 firewalld
bash
#查看当前放行端口
firewall-cmd --list-all
两种处理方式(练习环境选其一)
1、临时放行端口(重启服务器失效)
bash
firewall-cmd --add-port=80/tcp
2、直接关闭防火墙(学习测试环境,简单粗暴)
bash
systemctl stop firewalld
systemctl disable firewalld
完整访问判断排查顺序(记笔记,排错顺序)
浏览器访问不通,按顺序排查,从上往下:
✅容器状态:docker ps 容器状态是 Up
✅服务器本机内部测试:curl 127.0.0.1:端口
如果 curl 本机都失败 → Docker 容器 /nginx 服务本身问题
✅Linux 防火墙:firewalld 放行对应端口,或者关闭
✅云服务器安全组:网页控制台放行宿主机映射出来的端口
注意:放行的是宿主机端口,不是容器内部 80 端口。
例如 -p 8082:80,安全组放行 8082,不是 80。
举例子:
docker run -d -p 8082:80 mynginx:v1
容器内部端口:80
宿主机对外端口:8082
安全组、firewalld,都要放行 8082
虚拟机(你现在 CentOS 虚拟机,不是云服务器)
你现在本地 VMware 虚拟机,没有云厂商安全组!只有 firewalld 一层。


只需要处理系统防火墙即可。
区分记忆:
本地虚拟机:只有 Linux firewalld
阿里云 / 腾讯云云服务器:安全组 + firewalld 两层防火墙
高频踩坑
安全组放行容器内部端口,不放宿主机端口 → 访问失败
curl 服务器内部 127.0.0.1 能通,外网浏览器打不开:90% 是安全组没开。
安全组改完有时候十几秒才生效。
简单总结一句话
云服务器对外暴露服务,安全组和系统防火墙都要考虑;虚拟机只需要管系统防火墙。放行的是宿主机映射后的端口

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐