docker run hello-world 原理与排错:Docker 环境验证黄金标准

docker run hello-world 原理与排错:Docker 环境验证黄金标准
1. 为什么“hello-world”不是玩具而是你 Docker 旅程里最严肃的一课刚装完 Docker桌面弹出“Docker Desktop is ready”的提示你点开终端敲下docker --version看到Docker version 24.0.7, build afdd53b心里一松——成了别急。这就像新买回一台烤箱只看了说明书封面就宣布“我会做蛋糕了”。docker --version只证明命令行工具在它不验证守护进程daemon是否真在后台呼吸不检验你的用户有没有权限向它发号施令更不确认镜像拉取、容器启动、标准输出重定向这一整条链路是否畅通无阻。真正的验证必须是一次端到端的、带状态反馈的、可观察的完整执行闭环。而docker run hello-world就是这个闭环的黄金标准。它不是教学演示不是功能展示它是一个精巧的诊断探针。Docker 官方团队把它设计成一个仅 2.4KB 的静态二进制文件打包进一个极简的镜像里。这个镜像没有依赖、不联网、不写磁盘、不监听端口它唯一要做的就是被加载、被执行、打印一段固定文本、然后干净退出。整个过程耗时通常在 1 秒以内但背后却串联起了 Docker 架构的全部核心组件CLI 客户端、守护进程通信、镜像仓库拉取、存储驱动overlay2 或 aufs、容器运行时runc、命名空间隔离、cgroups 资源限制。任何一个环节卡住你都会立刻看到明确的错误信息而不是一个模糊的“没反应”。我见过太多人跳过这一步直接去跑nginx或redis结果卡在权限错误上折腾两小时最后发现只是忘了把用户加进docker组。也见过新手在公司内网环境反复失败以为是 Docker 坏了其实是代理配置没生效而hello-world的报错信息里清清楚楚写着failed to resolve host docker.io。它用最轻的代价给你最重的确定性。所以别把它当成一个“Hello World”式的入门仪式把它当作你 Docker 环境的第一次“心电图检查”。当那几行绿色文字稳稳地印在终端上你才真正拿到了进入容器世界的入场券。接下来的所有操作——构建镜像、编排服务、调试网络——都建立在这个确定性的基石之上。没有它一切皆是空中楼阁。2. 核心细节解析与实操要点从命令到字节的全链路拆解2.1docker run hello-world这一行命令背后到底发生了什么很多人以为这只是一个简单的命令执行其实它触发了一套精密协作的自动化流水线。我们来一层层剥开它的外壳看看每个环节的职责和关键细节。第一阶段客户端解析与本地缓存查询当你敲下回车Docker CLI 首先会解析hello-world这个参数。它默认补全为hello-world:latest即最新版本的官方镜像。接着CLI 会向本地的 Docker daemon 发起一个GET /images/hello-world:latest/json的 HTTP API 请求。Daemon 收到后会立即扫描本地/var/lib/docker/image/overlay2/imagedb/content/sha256/Linux或~/Library/Containers/com.docker.docker/Data/vms/0/data/docker/image/overlay2/macOS下的镜像元数据数据库。这个查询是毫秒级的因为只是读取一个 JSON 文件。如果命中缓存CLI 会收到一个包含镜像 ID、大小、创建时间的完整响应如果未命中Daemon 会返回一个 404 错误此时 CLI 才会启动第二阶段。第二阶段镜像拉取Pull与分层校验一旦确认本地没有CLI 会发起POST /images/create?fromImagehello-worldtaglatest请求。Daemon 接收到后会连接 Docker Hub 的 registry APIhttps://registry.hub.docker.com/v2/。这里的关键在于hello-world镜像只有一个 layer其 manifest 文件manifest.json非常小里面只定义了一个config文件和一个layer的 SHA256 哈希值。Daemon 会先下载这个config文件约 1KB再根据其中的layer.digest去拉取那个 2.4KB 的 tar.gz 层。拉取过程中Daemon 会实时计算下载内容的 SHA256并与 manifest 中声明的哈希值比对。任何不一致都会导致拉取中止并报错invalid checksum这是 Docker 保证镜像完整性和安全性的第一道防线。整个拉取过程你看到的进度条其实是 Daemon 在向 CLI 回传pull progress的流式事件。第三阶段容器创建Create与运行Start镜像就位后CLI 会发送POST /containers/create请求附带一个包含大量参数的 JSON body。这个 body 里最关键的几个字段是Image: hello-world:latest指定基础镜像Cmd: [/hello]覆盖镜像默认的 ENTRYPOINT直接执行/hello二进制AttachStdout: true, AttachStderr: true要求将容器的标准输出和错误流 attach 到当前 CLI 进程这样你才能在终端上看到文字Tty: false不分配伪终端因为/hello不需要交互式 shellDaemon 收到后会调用runc工具在宿主机上创建一个新的进程。runc会为这个进程设置Mount Namespace将镜像的 rootfs即那个 2.4KB 的 layer 解压后的目录挂载为该进程的根目录/PID Namespace让该进程在自己的 PID 空间里成为 PID 1Network Namespace默认使用none网络模式不配置任何网络接口User Namespace默认映射为 root 用户所以/hello以 root 权限运行但它什么都不做所以很安全最后runc启动/hello进程它的 stdout 被重定向到一个管道Daemon 通过这个管道持续读取数据并通过 WebSocket 或 Unix Socket 将其转发给 CLICLI 再原样打印到你的终端。第四阶段优雅退出与状态归档/hello程序执行完毕exit(0)。runc检测到 PID 1 进程退出会向 Daemon 发送一个container exited事件。Daemon 将该容器的状态从running更新为exited并将其元数据退出码、启动时间、结束时间持久化到本地数据库。注意容器并没有被删除它只是停止了。你可以随时用docker ps -a看到它状态是Exited (0) 2 minutes ago。这个设计让你可以事后检查容器的完整生命周期是调试的基础。提示hello-world的退出码永远是0代表成功。如果你看到Exited (1)那说明程序本身崩溃了这在hello-world里几乎不可能发生一旦出现基本可以断定是底层运行时如 runc或内核模块如 overlayfs存在严重问题。2.2 输出信息的逐行解码每一行都是一个诊断信号成功的hello-world输出绝非一堆装饰性文字它是一份结构化的诊断报告。我们来逐行解读告诉你每句话背后的技术含义Unable to find image hello-world:latest locally这行告诉你Docker CLI 在本地镜像库中没有找到hello-world:latest。这是一个正面信号证明你的本地缓存是干净的或者你第一次运行。如果这行没出现而是直接跳到了下面的 “Hello from Docker!”说明镜像已存在本次是纯本地运行验证的是容器启动能力而非完整的拉取-运行链路。latest: Pulling from library/hello-world ... Status: Downloaded newer image for hello-world:latest这三行是拉取阶段的完整日志。library/hello-world是 Docker Hub 上的完整路径library/前缀表示这是官方仓库由 Docker 官方维护和签名。中间的...是实际的下载进度显示了 layer 的 ID 和大小。最后一行Downloaded newer image是关键它确认了拉取动作完成且成功。如果这里卡住或报错问题一定出在网络、代理或 DNS 上。Hello from Docker! This message shows that your installation appears to be working correctly.这是核心诊断结论。它不是一句客套话而是hello-world程序内部逻辑的直接输出。这个程序在启动后会主动向 Docker daemon 查询自身所处的容器环境信息如HOSTNAME,PATH并确认所有必要的系统调用如clone(),mount()都能成功执行。只有当所有这些自检都通过它才会打印这行。所以看到它等于收到了来自容器内部的“健康证明”。To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the hello-world image from the Docker Hub. (The image was not found locally, so it was pulled from the hub.) 3. The Docker daemon created a new container from that image. 4. The Docker daemon streamed the output of the containers application to the Docker client. 5. The Docker client displayed that output on your terminal.这五步是整个流程的教科书式总结。它之所以重要是因为它为你提供了一个标准化的故障排查清单。当你遇到问题时不要慌就按这五步逐一反向检查第 1 步失败→ 检查dockerd进程是否在运行CLI 是否能连上 socket。第 2 步失败→ 检查网络、代理、DNS、防火墙。第 3 步失败→ 检查磁盘空间、存储驱动配置、SELinux/AppArmor 策略。第 4 步失败→ 检查容器内核模块如overlay是否加载runc版本是否兼容。第 5 步失败→ 检查终端编码、CLI 版本、是否有恶意的 shell hook 劫持了输出。You can now start creating and running your own Docker containers.这是行动号召也是能力边界声明。它意味着你已经拥有了运行一个最简单容器的全部能力。下一步你需要学习的不再是“能不能”而是“怎么建”、“怎么管”、“怎么连”。注意hello-world的输出里永远不会出现 IP 地址、端口号、进程 ID 或任何动态生成的信息。它的所有文本都是硬编码在二进制里的。这是为了确保输出的绝对可预测性和可比性。任何额外的、不可预期的输出都意味着你的环境被篡改了比如安装了某些有副作用的 Docker 插件这本身就是一种安全隐患。3. 实操过程与核心环节实现手把手带你走通每一个环节3.1 全平台实操指南从零开始一次成功现在让我们把理论付诸实践。以下步骤经过我在 macOS Ventura、Ubuntu 22.04 和 Windows 11WSL2上的反复验证确保每一步都精准、可复现。请严格按顺序操作不要跳步。第一步确认基础环境在终端macOS/Linux或 PowerShellWindows中先执行which docker # 或 Windows 上 where docker如果返回一个路径如/usr/bin/docker或C:\Program Files\Docker\Docker\resources\bin\docker.exe说明 CLI 已安装。如果报错command not found请先去官网下载对应平台的安装包。切记Windows 用户务必选择“Docker Desktop for Windows”而不是旧版的 Docker Toolbox后者已废弃。第二步启动守护进程macOS打开“Docker Desktop”应用。你会在右上角菜单栏看到一个鲸鱼图标。当图标变为稳定的蓝色且没有旋转动画时表示 daemon 已就绪。你也可以在终端运行docker info | head -n 5如果能看到Server Version: 24.0.7等信息就成功了。Linux以 root 权限运行sudo systemctl status docker。如果看到active (running)说明服务已启动。如果看到inactive (dead)则运行sudo systemctl start docker并启用开机自启sudo systemctl enable docker。Windows双击桌面上的 Docker Desktop 图标。首次启动会要求你登录 Docker Hub 账号可选但建议注册一个免费账号并可能需要重启 WSL2如果使用。等待右下角通知区域的鲸鱼图标稳定显示。第三步执行终极验证现在终于到了激动人心的时刻。在终端中输入并执行docker run hello-world请务必注意不要加任何其他参数不要用sudo除非你明确知道为什么要加也不要尝试docker run -it hello-world。保持命令的绝对纯净这是获得最准确诊断结果的前提。第四步观察与记录执行后你会看到类似这样的输出为节省篇幅此处为精简版实际会更长Unable to find image hello-world:latest locally latest: Pulling from library/hello-world 2db29710123e: Pull complete Digest: sha256:c5515758d4c5e1e838e9cd307f6c6a0d620b5e07e6f927b07d05f6d12a1ac8d7 Status: Downloaded newer image for hello-world:latest Hello from Docker! This message shows that your installation appears to be working correctly. ...关键观察点第一行Unable to find image...是否出现应出现Pull complete是否显示应显示Status: Downloaded newer image是否出现应出现Hello from Docker!是否清晰可见必须出现最后一行是否是exited with code 0在docker ps -a的输出里查看应为0如果以上所有条件都满足恭喜你Docker 环境 100% 就绪。你可以放心进入下一阶段。第五步清理与验证可选但推荐虽然hello-world容器很小但养成良好的清理习惯很重要。运行docker ps -a | grep hello-world你会看到一行类似a1b2c3d4e5f6 hello-world:latest /hello 2 minutes ago Exited (0) 2 minutes ago hopeful_kare的输出。记下最前面的容器 IDa1b2c3d4e5f6。然后运行docker rm a1b2c3d4e5f6这会删除这个已退出的容器。再次运行docker ps -a | grep hello-world应该没有任何输出。这证明你已经掌握了容器的生命周期管理创建run、停止自动、删除rm。实操心得我第一次在客户现场部署时就因为没做这一步清理导致docker ps -a里堆积了上百个hello-world容器虽然不影响功能但让客户觉得“这东西很脏”。后来我把docker rm $(docker ps -aq --filter ancestorhello-world)加进了我的初始化脚本一劳永逸。3.2 深度定制如何自己构建一个“hello-world”理解了官方镜像的原理下一步就是亲手造一个。这不仅能加深理解还能让你为后续项目打下坚实基础。我们来构建一个功能完全相同但完全由你掌控的my-hello-world。第一步创建项目目录mkdir my-hello-world cd my-hello-world第二步编写一个极简的 C 程序创建文件hello.c#include stdio.h int main() { printf(Hello from MY Docker!\n); printf(This proves YOUR installation is working.\n); return 0; }这个程序比官方的还多了一行是为了让你一眼就能区分。第三步编写 Dockerfile创建文件Dockerfile注意没有后缀# 使用一个最小的、只含 C 运行时的镜像作为基础 FROM scratch # 将编译好的二进制文件复制进来 COPY hello / # 声明容器启动时执行的命令 CMD [/hello]scratch是 Docker 中最小的镜像它就是一个空的文件系统。这意味着你复制进去的hello必须是静态链接的不能依赖任何外部.so库。第四步编译与构建在 Linux/macOS 上我们需要用gcc静态编译gcc -static -o hello hello.c然后构建镜像docker build -t my-hello-world .docker build命令会读取Dockerfile按顺序执行指令。FROM scratch创建一个空的镜像层。COPY hello /将当前目录下的hello二进制文件复制到镜像的根目录/下。CMD [/hello]将/hello设置为该镜像的默认启动命令。构建完成后运行docker run my-hello-world你应该看到Hello from MY Docker! This proves YOUR installation is working.这就是你的第一个 Docker 镜像它和官方的hello-world在功能上完全等价但它的每一个字节都出自你的手。你可以用docker images | grep my-hello-world查看它的大小通常只有 800KB 左右远大于官方的 2.4KB这是因为我们的gcc静态链接包含了更多运行时库。但这不重要重要的是你亲手完成了从源码到镜像的全过程。实操心得很多新手在gcc -static这一步会失败报错ld: cannot find -lc。这是因为你的系统缺少glibc-static包。在 Ubuntu 上运行sudo apt-get install libc6-dev即可解决。在 macOS 上由于clang默认不支持-static建议直接用 Linux 虚拟机或 WSL2 来做这一步。这恰恰说明了为什么官方hello-world要用 Go 语言编写——Go 编译出来的二进制天生就是静态链接的跨平台性无敌。4. 常见问题与排查技巧实录那些年我们踩过的坑4.1 “docker: command not found” —— 最经典的幻觉现象在终端输入docker --version系统报错bash: docker: command not found。真相这不是 Docker 没装而是你的 shell 找不到docker这个可执行文件在哪里。它就像你家的钥匙明明在桌上但你翻遍了口袋和包都找不到因为你根本没去桌上找。排查与解决定位安装路径macOSDocker Desktop 默认安装在/usr/local/bin/docker。检查这个路径是否存在ls -l /usr/local/bin/docker。如果不存在说明 Docker Desktop 没有正确安装或没完成初始化。重新运行安装包确保勾选了“Add Docker commands to your PATH”。Linuxwhich docker应该返回/usr/bin/docker或/usr/local/bin/docker。如果没返回说明你用curl下载的二进制包没放到 PATH 里。把它复制过去sudo cp docker /usr/local/bin/。Windowswhere docker应该返回C:\Program Files\Docker\Docker\resources\bin\docker.exe。如果没返回检查 Docker Desktop 的安装目录然后将该目录C:\Program Files\Docker\Docker\resources\bin\添加到系统的PATH环境变量中。刷新 shell 环境修改了 PATH 后不要关闭终端在当前终端里运行source ~/.zshrcmacOS Catalina或source ~/.bashrcLinux让新的 PATH 生效。如果还是不行最简单粗暴的方法是关掉所有终端窗口重新打开一个新的。注意在 macOS 上如果你用的是 zsh默认而你修改的是~/.bash_profile那么source ~/.bash_profile是无效的。一定要确认你修改的是当前 shell 的配置文件。运行echo $SHELL可以查看当前 shell。4.2 “Permission denied while trying to connect to the Docker daemon socket” —— Linux 用户的头号敌人现象docker run hello-world报错Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.43/images/hello-world:latest/json: dial unix /var/run/docker.sock: connect: permission denied。真相Docker daemon 监听的 Unix Socket 文件/var/run/docker.sock的权限是srw-rw----属于root:docker组。你的普通用户账户既不是root也不在docker组里所以没有读写权限。这就像你家的门锁只有主人root和管家docker 组成员有钥匙。排查与解决检查用户组运行groups看输出里有没有docker。如果没有执行sudo usermod -aG docker $USER这条命令的意思是“把当前用户$USER添加到docker组里并且是追加-a不是替换-G”。生效组权限这是最关键的一步90% 的人在这里失败usermod命令只是修改了系统数据库但你的当前登录会话session并不会自动更新组成员信息。你必须完全退出当前的图形界面或终端会话然后重新登录。在服务器上可以exit退出 SSH再重新连接。在桌面系统上注销Log Out再登录。仅仅关闭终端窗口是不够的终极验证重新登录后运行groups确认docker出现在列表里。然后运行docker run hello-world应该一切顺利。实操心得我曾经在一个客户的生产服务器上因为没重启会话反复执行了 7 次usermod命令最后发现groups输出里还是没有docker。当时真是又气又笑。后来我写了个一键脚本里面强制包含echo 请注销并重新登录的提示再也不犯这个错了。4.3 “Cannot connect to the Docker daemon” —— 守护进程的沉默现象docker run hello-world报错Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?。真相Docker daemon 进程dockerd根本没有在后台运行。CLI 就像一个电话客服拨号过去但对方的电话根本没开机。排查与解决Linux检查服务状态sudo systemctl status docker。如果看到inactive (dead)说明服务没启动。启动服务sudo systemctl start docker。设置开机自启推荐sudo systemctl enable docker。如果启动失败看错误日志sudo journalctl -u docker -n 50 --no-pager通常会提示具体原因比如Failed to start docker.service: Unit docker.service not found说明 Docker 根本没安装。macOS/Windows检查系统托盘/菜单栏。macOS 在右上角Windows 在右下角必须看到一个静止的、不旋转的鲸鱼图标。如果图标在旋转说明它正在启动中请耐心等待 30-60 秒。如果图标消失或变成灰色说明 Docker Desktop 应用已崩溃或被你手动退出了。双击 DockmacOS或开始菜单Windows里的 Docker Desktop 图标重新启动它。如果重启后图标依然不出现尝试完全卸载重装。Docker Desktop 的卸载非常干净不会残留任何配置。提示在 macOS 上有时 Docker Desktop 会因为 macOS 的 SIP系统完整性保护机制而无法正常启动。这时打开“系统设置” - “隐私与安全性” - “完全磁盘访问”确保 Docker Desktop 在列表中并已勾选。这是 macOS 13 的常见问题。4.4 “Failed to pull image” —— 网络世界的迷雾现象docker run hello-world卡在Pulling from library/hello-world或者报错Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting for connection。真相你的机器无法连接到 Docker Hub 的镜像仓库。这通常不是 Docker 的问题而是你网络环境的问题。排查与解决基础网络检查首先确认你能正常上网。ping google.com或curl -I https://www.docker.com。如果这些都失败那就是你的网络本身有问题先解决网络。DNS 检查Docker Hub 的域名registry-1.docker.io必须能被正确解析。运行nslookup registry-1.docker.io # 或 dig registry-1.docker.io如果返回NXDOMAIN或超时说明 DNS 有问题。临时修改/etc/resolv.confLinux/macOS或网络设置Windows将 DNS 服务器改为8.8.8.8Google或114.114.114.114国内。代理配置企业/学校网络Linux编辑/etc/systemd/system/docker.service.d/http-proxy.conf添加[Service] EnvironmentHTTP_PROXYhttp://your-proxy:port/ EnvironmentHTTPS_PROXYhttp://your-proxy:port/然后重载配置sudo systemctl daemon-reload sudo systemctl restart docker。macOS/Windows (Docker Desktop)打开 Docker Desktop 设置 - “Resources” - “Proxies”填入你的代理地址和端口点击 “Apply Restart”。镜像加速器中国大陆用户由于国际网络原因直连 Docker Hub 速度极慢。强烈建议配置国内镜像加速器如阿里云、腾讯云提供的加速地址。在 Docker Desktop 设置中找到 “Docker Engine”在 JSON 配置中添加{ registry-mirrors: [https://your-mirror-id.mirror.aliyuncs.com] }保存后重启 Docker Desktop。这能将拉取速度从几分钟提升到几秒钟。实操心得我在一家大型国企做培训时所有学员的电脑都连着同一个内网但只有 3 台机器能成功拉取hello-world。最后发现是 IT 部门给这 3 台机器单独配置了白名单允许它们访问外网。其他机器的流量被防火墙无声丢弃了。所以当你在企业环境遇到这个问题第一反应不应该是“Docker 坏了”而是“我的网络策略是什么”。5. 从“Hello World”出发你的 Docker 成长路线图docker run hello-world的成功不是一个终点而是一张通往广阔世界的船票。它证明了你的引擎已经点火现在是时候规划航线了。这条路线图是我过去十年带过上百个团队、数千名开发者后总结出的最平滑、最高效的成长路径。第一站拥抱交互式容器1 小时hello-world是单向的、一次性的。下一步你要学会与容器“对话”。运行docker run -it ubuntu:22.04 bash-it是两个标志的组合-iinteractive让容器保持 STDIN 打开-ttty分配一个伪终端。你将直接进入一个 Ubuntu 容器的 Bash shell。在这里你可以apt update apt install -y curl安装软件感受容器的“洁净”与“隔离”。curl ifconfig.me测试容器的网络连通性。touch /tmp/test.txt ls /tmp创建文件观察它只存在于这个容器内。exit退出容器回到你的宿主机。你会发现刚才安装的curl、创建的test.txt在宿主机上都不存在。这就是容器的“沙盒”本质。这一步的价值在于它把抽象的概念隔离、镜像、容器变成了你指尖可触的现实。你不再是在读文档而是在“生活”在容器里。第二站探索镜像宇宙30 分钟Docker Hub 就是你的应用商店。不要只盯着ubuntu和nginx。花半小时用命令行探索# 搜索 Python 相关的官方镜像 docker search --filter is-officialtrue python # 查看某个镜像的详细信息比如官方 Python 3.11 docker pull python:3.11-slim docker inspect python:3.11-slim | jq .[0].Config.Labels # 运行一个 Python 容器执行一行代码 docker run python:3.11-slim python -c print(Hello from Python in Docker!)你会发现官方镜像都有清晰的标签slim,alpine,buster它们代表了不同的基础操作系统和体积。slim是基于 Debian 的精简版alpine是基于 Alpine Linux 的超轻量版 30MB。选择哪个取决于你对体积、安全性和兼容性的权衡。第三站构建你的第一个应用镜像2 小时别再用别人的镜像了。现在轮到你来创造。创建一个简单的 Python Web 应用app.pyfrom flask import Flask app Flask(__name__) app.route(/) def hello(): return Hello from my FIRST Dockerized App! if __name__ __main__: app.run(host0.0.0.0:5000)然后写一个Dockerfile# 使用官方 Python 运行时作为父镜像 FROM python:3.11-slim # 设置工作目录 WORKDIR /app # 复制 requirements.txt 并安装依赖如果有 # COPY requirements.txt . # RUN pip install --no-cache-dir -r requirements.txt # 复制应用代码 COPY app.py . # 暴露端口 EXPOSE 5000 # 运行应用 CMD [python, app.py]构建并运行docker build -t my-first-app . docker run -p 5000:5000 my-first-app然后在浏览器打开http://localhost:5000。看到那个Hello from my FIRST Dockerized App!时那种成就感是任何教程都无法给予的。这标志着你已经从 Docker 的“使用者”正式晋级为“构建者”。第四站理解编排与协作长期单个容器是玩具多个容器协同工作才是生产。docker-compose.yml是你下一个必学的利器。它用一个 YAML 文件描述一组容器Web、DB、Cache如何一起启动、如何相互通信。例如一个简单的 WordPress 站点只需要 20 行 YAML就能同时启动 Nginx、PHP-FPM 和 MySQL并让它们自动连接。这背后是 Docker 的网络bridge和卷volume技术在默默支撑。这条路没有捷径但每一步都坚实。hello-world是你旅程的起点而你现在已经站在了甲板上海风拂面前方是星辰大海。记住所有伟大的容器化应用都始于这行看似简单的命令。你已经证明了自己有能力驾驭它剩下的就是尽情创造。