十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Docker 创建容器入门:镜像拉取、docker run 与生命周期实战

Docker 创建容器入门:镜像拉取、docker run 与生命周期实战 很多人第一次接触 Docker最想干的事就是创建容器装好 Docker Desktop 或 Docker Engine打开终端然后迫不及待敲下第一条命令。但问题也往往从这里开始镜像没拉下来、端口冲突、容器起来又退出、数据卷路径写错、Windows 和 macOS 的虚拟化没开最后怀疑自己是不是不适合学 Docker。其实创建容器这件事本身并不难难的是把镜像、容器、网络、存储、权限这些概念在一个具体操作里串起来。小白实操入门的第一篇我不打算讲太多底层源码而是围绕“如何创建容器”这条主线把环境准备、镜像拉取、docker run 参数、实战案例、生命周期管理和常见故障排查一次讲透。只要你手上有台能装 Docker 的电脑跟着步骤做就能把第一个容器真正跑起来并且知道每一步为什么这么写。1. 创建容器之前先把镜像、容器、Docker Desktop 这几件事捋顺1.1 镜像不是容器容器也不是镜像我见过不少新手把镜像和容器当成同一个东西结果删除镜像时发现删不掉或者停止容器后以为镜像也没了。你可以把镜像理解成“模具”或“安装包”容器则是用这个模具开出来、正在运行或已经停止的“零件”。镜像是只读的容器在镜像之上加了一层可写层所以同一个 Nginx 镜像可以创建三个不同名字、不同端口、不同配置的容器彼此之间互不影响。创建容器的本质就是让 Docker 基于某个镜像启动一个进程并给这个进程套上隔离的文件系统、网络、进程空间和资源限制。你后面执行docker run、docker create、docker start其实都是在围绕“镜像 - 容器”这条链路做操作。这里还有一个容易混淆的点容器里必须有一个主进程。如果这个主进程退出了容器就会变成 Exited 状态。很多小白创建容器后执行docker ps看不到以为创建失败实际上可能是容器启动后主进程立刻结束。比如你跑一个ubuntu镜像但不给它任何常驻命令它会启动一个 bash发现没有交互终端就退出。这不是 Docker 坏了而是容器的生命周期跟着主进程走。理解这一点后面排查“容器启动即退出”会轻松很多。1.2 Windows 和 macOS 用户Docker Desktop 安装完先做这三项检查如果你在 Windows 或 macOS 上学习最省心的路径通常是安装 Docker Desktop。Windows 用户还要注意家庭版、专业版以及 WSL2 的差异现在主流做法是启用 WSL2 后端。安装完成后不要急着敲命令先做三项检查。第一确认 Docker 服务已经启动。打开终端执行docker version如果能看到 Client 和 Server 两段信息说明客户端和守护进程都正常。只看到 Client 而 Server 报错通常是 Docker Desktop 没启动或者当前用户没有连上 Docker 守护进程。第二检查虚拟化是否开启。Windows 上如果 BIOS 里没开虚拟化Docker Desktop 可能提示virtualization support not detected或者直接启动失败。这个不是 Docker 命令能解决的需要进 BIOS 打开 Intel VT-x 或 AMD-V。macOS 一般不需要手动开虚拟化但旧版本系统或安全软件冲突也可能导致 Docker Desktop 起不来。第三确认镜像加速或网络能拉取镜像。国内网络环境下直接从 Docker Hub 拉镜像可能很慢甚至超时。你可以配置镜像加速器但注意不要使用任何不合规的网络工具。企业内网用户则要确认代理和证书设置否则docker pull会卡住。注意Docker Desktop 的图形界面只是管理工具真正的操作入口还是终端。不要只会在界面上点“Run”命令行才是后面走远的基础。1.3 容器创建链路pull、create、start、run 各干什么创建容器并不是一条命令凭空变出来的它背后有一条清晰链路docker pull从镜像仓库把镜像下载到本地。docker create基于镜像创建一个容器但此时不启动。docker start启动已经创建的容器。docker run相当于pull如果本地没有createstart的组合命令最常用。docker exec进入正在运行的容器执行命令不是创建容器而是操作已有容器。很多人只记docker run这当然可以但调试时拆开更清楚。比如你要先确认容器配置对不对可以用docker create创建但不启动然后docker inspect看配置确认没问题再docker start。而docker run适合日常快速启动。理解这条链路后你就不会把“拉镜像失败”和“创建容器失败”混为一谈。2. 第一次创建容器从拉取镜像到 docker run 跑起来2.1 拉镜像前先选对标签别上来就用 latest创建容器的第一步通常是拿到镜像。你可以直接docker run nginxDocker 会自动拉取nginx:latest。但生产或学习环境里我不建议无脑用latest。latest不是“最新稳定版”的保证它只是一个默认标签可能今天拉到的和下周拉到的不是同一个版本。对新手来说最稳妥的方式是明确版本比如docker pull nginx:1.25 docker pull mysql:8.0 docker pull redis:7.2拉取完成后用下面命令查看本地镜像docker images你会看到 REPOSITORY、TAG、IMAGE ID、CREATED、SIZE 几列。这里有个经验镜像 ID 才是唯一标识标签只是人类可读的别名。同一个镜像可以打多个标签。删除镜像时如果某个容器还在使用它普通docker rmi会失败需要先删容器或强制删除。强制删除不是好习惯容易留下悬空镜像和混乱依赖。另外镜像安全要从拉取阶段就注意。尽量使用官方镜像或可信组织维护的镜像不要随便拉陌生人的镜像就跑。后面我会讲几个基本的镜像安全检查动作。2.2 用 docker run 创建并启动一个 Nginx 容器现在来跑第一个真正有用的容器。假设你已经拉取了nginx:1.25执行docker run -d --name my-nginx -p 8080:80 nginx:1.25这条命令拆开看docker run创建并启动容器。-d后台运行终端不会被占用。--name my-nginx给容器起名字不写的话 Docker 会随机生成比如pedantic_einstein。-p 8080:80把宿主机 8080 端口映射到容器 80 端口。nginx:1.25指定镜像和标签。执行后用docker ps查看运行中的容器。如果看到my-nginx状态是 Up就说明创建成功。接着打开浏览器访问http://localhost:8080应该能看到 Nginx 欢迎页。如果访问不了先检查端口是否被占用、Docker Desktop 是否运行、防火墙是否拦截。这里有一个细节-p 8080:80中冒号前面是宿主机端口后面是容器端口。写反了就会变成把容器 8080 映射到宿主机 80结果你访问 8080 反而没反应。新手最容易在这里翻车。2.3 docker create docker start 拆分操作适合调试如果你想更清楚地看到“创建”和“启动”是两步可以这样docker create --name debug-nginx -p 8081:80 nginx:1.25 docker start debug-nginxdocker create执行后不会启动容器docker ps看不到但docker ps -a能看到状态是 Created。这时你可以用docker inspect debug-nginx查看它的网络、挂载、环境变量、端口映射等配置。确认无误后再docker start。这种方式在排查复杂容器时很有用因为你可以先检查配置避免一上来就启动失败。停止容器用docker stop debug-nginx删除容器用docker rm debug-nginx如果容器还在运行需要先停止再删除或者用docker rm -f debug-nginx强制删除。强制删除适合测试环境生产环境要谨慎。2.4 容器命名、后台运行与前台运行的选择容器命名不是小事。默认随机名虽然能跑但后面你要进入容器、看日志、做编排时名字就是你的坐标。我建议给容器起有意义的名字比如mysql-dev、redis-cache、nginx-web。名字在同一个 Docker 守护进程内必须唯一重复创建会报Conflict. The container name /xxx is already in use。后台运行-d适合服务类容器比如 Nginx、MySQL、Redis。前台运行适合临时调试比如docker run --rm -it alpine sh-it让容器有交互终端--rm表示退出后自动删除容器。用 Alpine 这种小镜像做实验很方便退出后不留垃圾。但要注意--rm和-d一起用通常没意义因为后台容器不会因为终端退出而删除。3. docker run 核心参数拆解端口、数据卷、环境变量、网络和资源限制3.1 端口映射 -p格式、冲突排查和只监听本机端口映射是创建容器时最常用的参数之一。完整格式有几种-p 8080:80 -p 127.0.0.1:8080:80 -p 8080:80/tcp第一种把宿主机所有网卡的 8080 映射到容器 80。第二种只绑定本机回环地址外部机器访问不了适合本地开发。第三种显式指定 TCP 协议。UDP 服务则要写/udp。如果启动时报Error response from daemon: Ports are not available: exposing port TCP 0.0.0.0:8080 - 0.0.0.0:0: listen tcp 0.0.0.0:8080: bind: address already in use说明宿主机 8080 已被占用。Windows 上可以用netstat -ano | findstr 8080查占用进程Linux/macOS 用lsof -i :8080或ss -lntp | grep 8080。解决方法要么停掉占用进程要么换一个宿主机端口比如-p 18080:80。注意容器端口不要随意改。Nginx 默认监听 80MySQL 默认 3306Redis 默认 6379。除非你改了容器内配置否则冒号后面的端口要和镜像默认端口一致。3.2 数据卷 -v 与 --mount持久化和文件共享的差别容器删了里面的数据通常也没了。要让数据留下来就要用数据卷。最常用写法docker run -d --name mysql-dev \ -v mysql-data:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD123456 \ mysql:8.0这里mysql-data是命名卷Docker 管理实际存储位置。你也可以绑定宿主机目录docker run -d --name nginx-web \ -v /host/path/html:/usr/share/nginx/html:ro \ -p 8080:80 \ nginx:1.25-v的绑定挂载格式是宿主机路径:容器路径:权限权限常见ro只读、rw读写。Windows 路径要特别注意比如D:/docker/html:/usr/share/nginx/html在 Git Bash 或 PowerShell 里路径写法可能不同。--mount是更推荐的现代写法语义更清楚docker run -d --name nginx-web \ --mount typebind,sourceD:/docker/html,target/usr/share/nginx/html,readonly \ -p 8080:80 \ nginx:1.25两者都能用但--mount在路径不存在时报错更明确-v可能会自动创建目录导致你以为挂载成功其实挂错了地方。新手排查挂载问题时先docker inspect看 Mounts 部分确认 Source 和 Destination 是不是你想要的。3.3 环境变量 -e、网络 --network、重启策略 --restart环境变量是创建容器时注入配置的重要手段。比如 MySQL 需要设置 root 密码-e MYSQL_ROOT_PASSWORD123456 -e MYSQL_DATABASEtestdb -e TZAsia/Shanghai时区问题很常见。很多容器默认 UTC日志时间和你本地差 8 小时。加-e TZAsia/Shanghai通常能解决 Java、MySQL 等容器的时区问题。如果镜像不支持 TZ就要挂载/etc/localtime或安装 tzdata。网络方面默认使用 bridge 网络。你可以创建自定义网络docker network create my-net docker run -d --name app --network my-net nginx:1.25同一个自定义网络里的容器可以用容器名互相访问这比默认 bridge 网络方便得多。后面做多容器应用时建议一开始就用自定义网络。重启策略也很关键--restart unless-stopped这个策略表示容器退出时自动重启除非你手动 stop。常见选项还有no、on-failure、always。本地开发用unless-stopped比较舒服机器重启后服务会自动起来。但要注意如果容器本身配置错误反复重启会刷日志先排查再设策略。3.4 资源限制 --memory、--cpus以及 docker-compose up 里的配置差异容器默认可以使用宿主机大量资源。如果不限制某个 Java 容器可能把内存吃满导致其他服务被拖垮。创建时可以直接限制docker run -d --name limited-nginx \ --memory512m \ --cpus1.0 \ nginx:1.25--memory限制内存--cpus限制 CPU 核数。还可以用--cpuset-cpus绑定具体 CPU 核心但新手先掌握前两个就够。查看容器资源占用docker stats如果你用 Docker Compose资源限制的写法不同。docker-compose up启动时deploy.resources在某些版本和模式下才生效普通docker-compose up可能忽略deploy段。更稳妥的方式是在docker-compose.yml里用mem_limit、cpus或者改用docker compose up并遵循新版规范。很多人问docker-compose up 限制容器配置为什么不生效原因就是 Compose 文件版本、命令版本和 Swarm 模式之间的差异。建议先用docker run把参数调明白再迁移到 Compose。4. 实战创建 MySQL 8.0、Redis、Nginx 和 Java 应用容器4.1 创建 MySQL 8.0 容器密码、数据目录、字符集MySQL 是小白最常创建的容器之一。下面这条命令可以直接抄docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORDRoot123456 \ -e MYSQL_DATABASEtestdb \ -e TZAsia/Shanghai \ -v mysql8-data:/var/lib/mysql \ --restart unless-stopped \ mysql:8.0 \ --character-set-serverutf8mb4 \ --collation-serverutf8mb4_unicode_ci这里有几个关键点。第一MYSQL_ROOT_PASSWORD必须设置否则容器可能启动失败。第二/var/lib/mysql一定要挂载否则删除容器后数据全丢。第三字符集参数要放在镜像名后面因为它们是传给 MySQL 主进程的参数。第四3306 端口如果本机已经装了 MySQL会冲突可以改成-p 13306:3306。启动后进入 MySQLdocker exec -it mysql8 mysql -uroot -p输入密码即可。如果连接报Access denied检查密码和环境变量是否写错。如果报Cant connect to local MySQL server先看容器日志docker logs mysql84.2 创建 Redis 容器密码、持久化和配置文件挂载Redis 容器创建也不复杂docker run -d \ --name redis7 \ -p 6379:6379 \ -v redis7-data:/data \ --restart unless-stopped \ redis:7.2 \ redis-server --appendonly yes --requirepass Redis123456--appendonly yes开启 AOF 持久化--requirepass设置密码。如果不设密码本地开发无所谓但只要端口暴露到公网就非常危险。Redis 未授权访问是经典安全问题别觉得“我就测试一下”没事。如果要挂载自定义配置文件-v D:/docker/redis/redis.conf:/usr/local/etc/redis/redis.conf redis:7.2 redis-server /usr/local/etc/redis/redis.confWindows 挂载文件时要注意共享驱动和路径权限。如果配置文件挂载后 Redis 启动失败先查看日志常见原因是配置文件路径写错或文件权限不可读。4.3 创建 Nginx 容器挂载静态目录和自定义配置Nginx 容器适合做静态网站、反向代理。创建命令docker run -d \ --name nginx-web \ -p 8080:80 \ -v D:/docker/nginx/html:/usr/share/nginx/html:ro \ -v D:/docker/nginx/conf.d:/etc/nginx/conf.d:ro \ --restart unless-stopped \ nginx:1.25把静态文件放到D:/docker/nginx/html浏览器访问http://localhost:8080就能看到。如果要改配置把自己的.conf放到conf.d目录然后docker exec nginx-web nginx -t docker exec nginx-web nginx -s reloadnginx -t检查配置语法reload平滑重载。不要直接重启容器除非配置错误导致进程挂了。很多小白改完配置不生效是因为挂载的目录不对或者宿主机文件没保存。4.4 Java 容器从 idea 打包 docker镜像 到运行容器Java 开发者常问IDEA 里打包 Docker 镜像后怎么创建容器通常流程是先在 IDEA 里用 Maven 或 Gradle 打出可执行 jar然后编写 DockerfileFROM eclipse-temurin:17-jre WORKDIR /app COPY target/myapp.jar app.jar EXPOSE 8080 ENTRYPOINT [java,-jar,/app/app.jar]构建镜像docker build -t my-java-app:1.0 .创建并启动容器docker run -d \ --name my-java-app \ -p 8080:8080 \ -e TZAsia/Shanghai \ -e SPRING_PROFILES_ACTIVEdev \ --memory1g \ --restart unless-stopped \ my-java-app:1.0如果你用 IDEA 的 Docker 插件可以在图形界面里构建镜像但底层还是执行docker build。创建容器时注意 JVM 内存参数比如-e JAVA_OPTS-Xms256m -Xmx512m要和--memory配合否则 JVM 可能被容器内存限制直接杀掉。查看日志docker logs -f my-java-app如果容器启动后立刻退出先看日志里是不是数据库连接失败、端口占用或配置文件缺失。5. 容器生命周期管理与常用命令速查5.1 查看、进入、停止、重启、删除容器创建容器只是开始日常管理更重要。常用命令如下操作命令说明查看运行中容器docker ps只看 Up 状态查看所有容器docker ps -a包括 Exited进入容器docker exec -it 容器名 sh推荐 sh 或 bash停止容器docker stop 容器名发送 SIGTERM超时后 SIGKILL启动已停止容器docker start 容器名不重新创建重启容器docker restart 容器名停止再启动删除容器docker rm 容器名需先停止强制删除docker rm -f 容器名运行中也删进入容器时如果镜像里没有 bash就用sh。Alpine 镜像默认只有 sh。不要用docker attach进入服务容器因为退出时可能把主进程也带停。docker exec是更安全的方式。5.2 日志、资源占用、网络和文件系统排查排查容器问题第一手资料是日志docker logs --tail 100 容器名 docker logs -f 容器名--tail看最近 100 行-f持续跟踪。如果日志没有输出可能是主进程没启动或者日志输出到了文件而不是标准输出。第二是资源docker stats第三是网络docker inspect 容器名 docker network inspect 网络名第四是文件系统docker diff 容器名docker diff能看到容器可写层相对镜像的变化比如新增、修改、删除了哪些文件。这个命令对排查“容器里改了配置但重启后丢失”很有帮助因为可写层没挂载出来时删除容器就全没了。5.3 镜像、容器、数据卷清理别让磁盘悄悄爆满Docker 用久了磁盘会被镜像、停止的容器、悬空卷、构建缓存吃掉。查看占用docker system df清理停止的容器、无用网络、悬空镜像和构建缓存docker system prune如果要连未使用的数据卷一起清docker system prune --volumes注意--volumes会删除未使用的数据卷可能包含数据库数据。执行前先确认没有重要数据。生产环境不要随手prune。单独删除镜像docker rmi 镜像名:标签如果提示 image is being used by running container先删容器再删镜像。也可以docker image prune清理悬空镜像。6. 新手最容易踩的坑常见问题与排查技巧实录6.1 端口被占用、容器启动即退出、名称冲突端口占用前面讲过换端口或停占用进程。容器启动即退出先看docker logs。常见原因有主进程命令错误、配置文件语法错误、依赖服务连不上、内存不足被 OOM Kill。名称冲突则删除旧容器或换个名字docker rm -f my-nginx排查容器退出码docker inspect 容器名 --format{{.State.ExitCode}}退出码 0 表示正常结束非 0 通常是异常。137 常表示被 SIGKILL可能是 OOM。143 表示收到 SIGTERM。把这些退出码和日志结合看定位会快很多。6.2 Docker Desktop 启动失败、虚拟化未开启、WSL 相关检查Windows 上 Docker Desktop 启动失败常见提示包括virtualization support not detected、WSL2 is not installed、Docker Desktop failed to start because virtualisation support wasnt detected。处理顺序进 BIOS 开启虚拟化。确认 Windows 功能里启用了“虚拟机平台”和“适用于 Linux 的 Windows 子系统”。安装或更新 WSL2 内核。确认 Docker Desktop 使用 WSL2 后端。重启电脑。如果还是不行查看 Docker Desktop 日志或者重置到出厂设置。注意重置会删除本地镜像和容器重要数据先备份。6.3 容器内网络不通、数据卷权限、时区错乱容器内网络不通先确认容器和宿主机网络模式。默认 bridge 下容器访问宿主机要用宿主机 IP不能写 localhost。自定义网络里可以用容器名互访。如果容器需要访问外部网络检查 DNS 配置和防火墙。数据卷权限问题在 Linux 上常见容器内进程用户和宿主机目录用户不一致导致读写失败。可以用-u指定用户或者调整宿主机目录权限。Windows 和 macOS 的 Docker Desktop 对文件共享有额外限制路径没加入共享目录会挂载失败。时区错乱加-e TZAsia/Shanghai或者挂载-v /etc/localtime:/etc/localtime:roJava 容器还要注意user.timezone可以在启动参数里加-Duser.timezoneAsia/Shanghai。6.4 镜像安全和容器安全的几个基本动作创建容器时就要有安全意识。第一尽量用官方镜像或可信镜像不用来历不明的镜像。第二固定版本标签不用latest方便审计和回滚。第三容器不要用 root 跑Dockerfile 里创建普通用户并用USER指定。第四限制资源避免一个容器拖垮宿主机。第五只暴露必要端口能绑127.0.0.1就不要绑0.0.0.0。第六敏感信息用环境变量或 secret 管理不要硬编码在镜像里。第七定期更新基础镜像扫描漏洞。第八数据卷权限最小化能只读就只读。镜像安全和容器安全不是大厂才要考虑的事个人项目同样重要。尤其是数据库容器端口暴露到公网加上弱密码很容易出问题。创建容器时多花两分钟检查参数后面能省很多麻烦。我个人现在建容器习惯先用docker run --rm -it做一次性测试确认镜像和命令没问题再换成-d --name --restart正式跑。遇到报错先docker logs再看docker inspect最后才怀疑 Docker 本身。这个顺序能解决大部分“创建容器失败”的问题。还有一个很实用的小技巧给每个容器加--label标记项目名比如--label projectblog后面用docker ps --filter labelprojectblog就能快速筛选容器多了也不会乱。
返回列表