【Docker】P2 Docker 命令:从Nginx部署到镜像分享的全流程指南

目录

欢迎来到本期的 Docker 教程!今天,我们将通过一个完整的流程化实例,带你走过 Docker 最核心的命令操作。

这个完整的流程为:

bash 复制代码
下载镜像 ➡️ 启动容器 ➡️ 修改应用 ➡️ 保存为新镜像 ➡️ 分享社区

镜像操作 (Image)

在 Docker 的世界里,一切都始于镜像 (Image)。你可以把镜像想象成一个"安装包",它是一个只读的模板,打包了运行应用所需的所有文件、依赖和配置。

镜像操作的主要命令包含:

  • 搜索镜像: docker search
  • 下载镜像: docker pull
  • 查看本地镜像: docker images
  • 删除镜像: docker rmi

检索与发现镜像

我们首先需要一个 Nginx 镜像。去哪里找呢?

  • 命令行检索docker search): 你可以使用 docker search nginx 来快速查找。
  • 更推荐: 访问 Docker Hub ,官方的镜像仓库。在这里搜索 nginx,你能直观的看到社区中所有的 nginx 镜像文件,包含:
    • Official Image (官方镜像): 带有 "Official" 标签,由 Docker 官方或应用官方维护,是我们的首选。
    • 社区镜像: 如 bitnami/nginx,由第三方维护。
    • 下载量 (Pulls) 和星标 (Stars): 这是判断镜像质量和受欢迎程度的重要依据。

下载镜像

让我们来使用官方的 nginx 镜像。

bash 复制代码
docker pull nginx

这个命令其实是一个简写。完整的命令格式是

bash 复制代码
docker pull [OPTIONS] NAME[:TAG|@DIGEST]
  • NAME 为镜像名,这里是 nginx。
  • [:TAG] 标签版本号,用于区分不同版本,选填,默认值为 :latest

查看本地镜像

下载完成后,我们使用 docker images 来查看本地已有的所有镜像。

bash 复制代码
docker images

你会看到一个列表:

bash 复制代码
REPOSITORY    TAG       IMAGE ID       CREATED        SIZE
nginx         latest    605c75e6e14c   3 weeks ago    141.5MB

让我们来详细解析每一列的含义:

  • REPOSITORY: 镜像仓库名称
  • TAG: 镜像标签(版本)
  • IMAGE ID: 镜像的唯一标识符,一个SHA256哈希值
  • CREATED: 镜像的创建时间
  • SIZE: 镜像文件占用的存储空间

删除镜像

如果某个镜像不再需要,可以使用 docker rmi (remove image) 删除它。

bash 复制代码
docker rmi [OPTIONS] [IMAGE_ID 或 REPOSITORY:TAG]
# 例如:docker rmi 605c75e6e14c
  • 注意: 如果一个镜像已经被某个容器(哪怕是已停止的容器)所使用,你是无法直接删除它的。你必须先删除所有使用该镜像的容器(详见下文 docker rm),或者在命令中 [OPTIONS] 部分使用 -f 强制删除(不推荐)。

容器操作 (Container)

有了镜像(安装包),我们就可以运行它,创建容器 (Container)。容器是镜像的运行时实例,是一个被隔离的、正在运行的应用环境。

容器操作的主要命令包含:

  • 启动容器: docker run
  • 查看容器: docker ps
  • 删除容器: docker rm
  • 停止容器: docker stop
  • 启动容器: docker start
  • 重启容器: docker restart

启动第一个容器

我们以最简单的方式启动 Nginx:

bash 复制代码
docker run nginx

问题出现: 你会发现,Nginx 启动后,你的命令行被占用了,日志在前台 不断输出。如果你按下 Ctrl+C 退出,容器也会随之停止。这显然不是我们想要的。

对此,我们的解决策略为在 run 命令中添加 -d 的 OPTIONS,具体原因我们稍后详述。

bash 复制代码
docker run -d nginx

查看容器

我们如何查看容器的状态?应用 docker ps 命令

  • docker ps:查看正在运行中的容器。
  • docker ps -a:查看所有的容器(包括已停止的)。

我们执行 docker ps

bash 复制代码
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS                      PORTS     NAMES
f3e6a0d4a7d1   nginx     "/docker-entrypoint...."   2 minutes ago    UP 2 minutes ago              jolly_bose

我们来解析 docker ps 展示出的列的含义:

  • CONTAINER ID:容器的唯一身份ID
  • IMAGE: 创建该容器所用的镜像
  • COMMAND: 容器启动时执行的命令,命令为内部命令,忽略
  • CREATED: 容器的创建时间
  • STATUS: 容器当前的状态。Up (运行中), Exited (已停止)。
  • PORTS: 容器的端口映射情况(稍后详述)。
  • NAMES: 容器的名称。如果你不指定,Docker 会分配一个随机的名称,如本示例中的 jolly_bose。

容器的生命周期管理

假设,我们来清理一个"已停止"的容器 my_app。

删除

bash 复制代码
docker rm my_app
# 或者使用 ID: docker rm f3e6a0d4a7d1

停止

docker rm 只能删除已停止的容器。如果容器正在运行,你需要先停止它:

bash 复制代码
# 假设有一个运行中的容器 "my_app"
docker stop my_app
# 或者使用 ID: docker stop f3e6a0d4a7d1

强制删除

如果你想一步到位,可以使用 -f 强制删除一个正在运行的容器(它会先 stoprm)。

bash 复制代码
docker rm -f my_app
# 或者使用 ID: docker rm -f f3e6a0d4a7d1

启动/重启

对于已停止的容器,可以使用 docker start 重新启动它。

bash 复制代码
docker start jolly_bose
# 或者使用 ID: docker start f3e6a0d4a7d1
docker restart jolly_bose # 重启
# 或者使用 ID: docker restart f3e6a0d4a7d1

深入 docker run

docker run 是 Docker 中最重要、最复杂的命令。我们现在用更合理的方式来启动 Nginx,解决之前遇到的两个问题:

  1. 前台运行,占用终端。
  2. 容器运行了,但我们从主机(电脑)无法访问。

为了解决上述两个问题,我们对 run 补充三个 OPTIONS:

  • -d:运行在后台
  • --name:起名
  • -p:端口映射

后台运行与命名

我们使用 -d (Detached) 参数,让容器在后台运行 。同时,使用 --name 给容器起一个好记的名字

bash 复制代码
docker run -d --name mynginx nginx

执行后,它只会返回一个容器ID,终端不会被占用。

此时,我们用 docker ps 查看:

bash 复制代码
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS     NAMES
a1b2c3d4e5f6   nginx     "/docker-entrypoint...."   5 seconds ago   Up 4 seconds   80/tcp    mynginx

STATUS 显示 UpNAMES 是我们指定的 mynginx

端口映射

现在容器在后台运行了。我们尝试在浏览器访问 http://localhost:80http://IP:80 失败了。

这是为什么呢? Docker 容器是隔离的。当你启动 mynginx 容器时,它在自己的"小黑屋"(独立的网络空间)里运行。Nginx 在这个小黑屋里监听了 80 端口。但是,我们的主机(你的电脑)并不知道这个小黑屋的存在,更无法访问它内部的 80 端口。

我们需要在主机和小黑屋之间架设一座桥梁,这就是端口映射 (-p)

bash 复制代码
# 语法: -p [宿主机端口]:[容器端口]

让我们删掉刚才的容器,用正确的方式重新启动:

bash 复制代码
# 1. 先停止并删除旧的
docker rm -f mynginx

# 2. 启动新容器,并添加端口映射
docker run -d --name mynginx -p 88:80 nginx

命令解析:

  • -p 88:80:将主机的 88 端口映射到容器的 80 端口。

现在,访问 http://localhost:88 的所有请求,都会被 Docker 自动转发到 mynginx 容器内部的 80 端口上。


修改 Nginx 首页

我们成功运行了 Nginx,但我们想修改默认的欢迎页面。此时,我们需要进入 mynginx 容器的内部,修改 Nginx 存放 index.html 的默认路径(通常是 /usr/share/nginx/html

主要涉及命令:

  • exec:进入到运行的容器中

进入运行中的容器

docker exec 命令允许我们在一个正在运行的容器中执行命令。

go 复制代码
docker exec -it mynginx /bin/bash

命令解析:

  • exec:进入容器固定指令,无他意
  • -it:这是两个参数的合写,无需深究:
    • -I:保持标准输入(STDIN)打开,允许我们与 shell 交互
    • -t:分配一个伪终端(pseudo-TTY),给我们一个像在真实服务器上操作的命令行提示符
  • mynginx:目标容器的名称
  • /bin/bash:我们要在容器内执行的命令。bash 是一个常见的 shell(有些轻量级镜像可能只有 /bin/sh)。

修改 html 文件

下一步,让我们来修改这份 index.html 文件:

bash 复制代码
cd /usr/share/nginx/html
# 查看文件:
ls
# 你会看到 index.html 和 50x.html
# 修改 index.html
echo "<h1>Hello! This is My Custom Nginx Page!</h1>" > index.html

验证与思考

此时,回到我们的浏览器,刷新 http://localhost:88。你会发现页面内容已经变成了 "Hello! This is My Custom Nginx Page!"。

实际上,读者在实操时也能感受到,每次都 exec 进去修改文件非常不方便,而且如果容器被删除(docker rm mynginx),所有修改都会丢失。 后面,我们将介绍更实用的技能,应用 Volume(卷)映射 (-v),将主机目录直接映射 到容器内,实现文件持久化和实时同步


保存容器为新的镜像文件

我们已经修改了 mynginx 容器。如果我们希望把这个"被修改过的状态"保存下来,变成一个新的镜像(例如 my-custom-nginx:1.0),以便将来重复使用或分享,该怎么办?

主要涉及命令:

  • commit:容器封装为镜像
  • save -o:镜像保存为 .tar 文件
  • load -I:.tar 文件导入为镜像

提交容器

docker commit 可以从一个容器的当前状态,封装打包为一个新的镜像。

bash 复制代码
docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

OPTIONS 常用选项:

  • -a:作者(Author),例如 "Your Name"
  • -m:提交信息(Message),类似 Git commit message

操作: 我们将正在运行的 mynginx 容器,提交为一个名为 my-custom-nginx、标签为 1.0 的新镜像。

bash 复制代码
docker commit -a "My Blog User" -m "Customized index.html" mynginx my-custom-nginx:1.0

验证: 执行 docker images

bash 复制代码
REPOSITORY          TAG       IMAGE ID       CREATED          SIZE
my-custom-nginx     1.0       a9c5b0c8d6e3   5 seconds ago    141.5MB  <-- 我们新创建的
nginx               latest    605c75e6e14c   3 weeks ago      141.5MB

我们成功制作了一个新镜像!

镜像的导入与导出

docker commit 创建的镜像是保存在本地的。如果我想把这个镜像拷贝给没有网络的同事,该怎么办?

  • 保存 (save) docker save 命令可以将一个镜像打包成一个 .tar 文件。

    bash 复制代码
    docker save -o my-nginx-image.tar my-custom-nginx:1.0
    • -o:指定输出文件(output)。执行后,当前目录会多一个 my-nginx-image.tar 文件。
  • 加载 (load): 你的同事拿到这个 .tar 文件后,使用 docker load 命令将其导入到自己的 Docker 中。

    bash 复制代码
    docker load -i my-nginx-image.tar
    • -i:指定输入文件(input)。执行后,再 docker images 就能看到 my-custom-nginx:1.0 了。

分享镜像

将镜像打包成 .tar 文件只适合小范围分享。如果我们希望全世界的开发者都能使用我们的镜像,我们应该将其分享到 Docker Hub。注意,需要科学上网。

主要涉及命令:

  • login:登录官方 Hub 系统
  • tag:更改镜像名称为符合官方格式要求的名称
  • push:将本地镜像推送到全世界都可以访问的 docker hub 社区中

登录仓库

首先,你需要在 Docker Hub 网站注册一个账号。假设你的用户名是 myusername。 然后在命令行登录:

bash 复制代码
docker login
# Username: myusername
# Password: 
# Login Succeeded

标记镜像

在登录完成后,标记镜像是非常关键的一步。如果你想把镜像推送到 Docker Hub,你必须给镜像一个符合官方规范要求的名称。我们可以应用 tag 命令来重命名。

Docker Hub 对于镜像名称的规范是:[你的用户名]/[仓库名]:[标签]

我们本地的镜像叫 my-custom-nginx:1.0,这不符合规范。我们需要使用 docker tag 给它起一个"别名":

bash 复制代码
# 格式: docker tag [源镜像] [目标镜像(带用户名)]
docker tag my-custom-nginx:1.0 myusername/my-custom-nginx:1.0

验证: 再次执行 docker images,你会发现:

bash 复制代码
REPOSITORY                    TAG       IMAGE ID
my-custom-nginx               1.0       a9c5b0c8d6e3
myusername/my-custom-nginx    1.0       a9c5b0c8d6e3  <-- 新增的、符合 Docker Hub 规范的
nginx                         latest    605c75e6e14c

它们共享同一个 IMAGE ID,本质上是同一个镜像的两个不同标签。

推送镜像

最后,将我们新标记的镜像推送到 Docker Hub:

bash 复制代码
docker push myusername/my-custom-nginx:1.0

等待上传完成后,任何人(包括你自己)在世界上任何一台安装了 Docker 的机器上,都可以通过执行 docker pull myusername/my-custom-nginx:1.0 来获取你修改过的 Nginx 镜像了!


总结

恭喜你!我们从一个最基础的 nginx 官方镜像出发,经历了 pull, run, ps, exec, commit, tag, push 等一系列核心操作,走完了一个完整的 Docker"开发-打包-分发"的生命周期。

你是否想继续了解如何使用 Dockerfile 来自动化构建镜像,或者如何使用 Volume 来管理持久化数据?请期待后续博文!


2025.10.30 G38 回北京途中

相关推荐
木卫二号Coding2 分钟前
affine+docker+postgresql+备份数据库
数据库·docker·容器
月明长歌4 分钟前
【码道初阶】【LeetCode 102】二叉树层序遍历:如何利用队列实现“一层一层切蛋糕”?
java·数据结构·算法·leetcode·职场和发展·队列
codingPower6 分钟前
制作ftl文件通过FreeMarke生成PDF文件(含图片处理)
java·开发语言·pdf
R.lin8 分钟前
Spring AI Alibaba 1.1 正式发布!
java·后端·spring
檀越剑指大厂10 分钟前
查看 Docker 镜像详情的几种常用方法
docker·容器·eureka
程序员阿明19 分钟前
spring security 6的知识点总结
java·后端·spring
李子园的李36 分钟前
Java函数式接口——渐进式学习
java
running up40 分钟前
Spring Bean生命周期- BeanDefinition 加载与 BeanFactoryPostProcessor BeanPostProcessor
java·后端·spring
222you1 小时前
Java线程的三种创建方式
java·开发语言
脸大是真的好~1 小时前
计算机408基础相关面试题-备用,不推荐
java