尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Docker容器化部署实战:从核心概念到安装配置与常用命令详解

Docker容器化部署实战:从核心概念到安装配置与常用命令详解 1. 从“为什么需要Docker”开始聊起如果你是一个开发者或者正在学习运维那么“Docker”这个词你肯定不陌生。但很多时候我们只是跟着教程敲命令docker run、docker ps却很少停下来想想为什么我们需要它它到底解决了什么痛点在我自己从手动部署到容器化部署的转变过程中Docker带来的最大改变不是命令本身而是一种思维和工作流的革新。在没有Docker之前我们经常遇到这样的场景开发环境跑得好好的代码一到测试环境就报错排查半天发现是Node.js版本不对或者运维同事拿着一份长长的环境配置文档小心翼翼地安装依赖生怕漏掉某个系统库。这种“在我的机器上能跑”的问题几乎成了软件开发的一个经典笑话。Docker的出现就是为了封装这个“环境”。它通过容器技术将应用及其所有依赖包括代码、运行时、系统工具、系统库和设置打包成一个标准化的单元。这个单元可以在任何安装了Docker引擎的计算机上一致地运行。你可以把它想象成一个极其轻量级的、便携式的虚拟机但它共享宿主机的操作系统内核因此启动更快、资源开销更小。理解了这一点再去看那些安装和配置步骤你就会明白每一步的目的而不仅仅是机械地复制粘贴命令。今天我就结合自己多年的使用经验从最基础的安装配置讲起再到那些真正高频、实用的命令帮你构建一个清晰、可操作的Docker知识框架。2. Docker核心概念扫盲镜像、容器与仓库在动手安装之前花几分钟搞清楚三个核心概念至关重要这能让你后面的学习事半功倍。很多新手容易在这里混淆。镜像Image你可以把它理解为一个只读的模板。这个模板包含了运行某个软件所需的所有内容——代码、运行时环境、库、环境变量和配置文件。例如一个Ubuntu镜像就是一个精简的Ubuntu root文件系统一个Nginx镜像则包含了编译好的Nginx程序及其运行环境。镜像是创建容器的基础本身是静态的、分层的。Docker使用联合文件系统UnionFS来构建镜像这意味着每一层都是只读的并且可以被多个镜像共享这极大地节省了存储空间。容器Container容器是镜像的运行实例。当你从镜像启动一个容器时Docker会在镜像的只读层之上添加一个可写的“容器层”。所有对运行中容器的修改如创建新文件、安装新软件都发生在这个可写层。容器可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的应用沙箱。关键点在于容器是短暂的。通常我们不应该把需要持久化的数据或状态保存在容器层而是通过“数据卷”来处理。仓库Registry仓库是集中存放镜像的地方类似于代码仓库GitHub。最大的公共仓库是Docker官方的Docker Hub上面有无数官方和个人维护的镜像。你也可以搭建私有的仓库用于存放企业内部的应用镜像。docker pull命令就是从仓库拉取镜像docker push则是将本地镜像推送到仓库。这三者的关系很简单从仓库拉取Pull镜像到本地然后用这个镜像创建Create并启动Run一个容器。一个镜像可以创建出多个同时运行的容器实例。3. 在不同操作系统上安装Docker引擎Docker引擎的安装因操作系统而异。这里我会覆盖最主流的三个平台Linux以Ubuntu为例、macOS和Windows。我会重点讲Linux因为它是生产环境中最常见的部署平台同时也会指出其他平台的关键注意事项。3.1 在Ubuntu/Linux上安装Docker这是最经典也是最重要的安装场景。生产环境的服务器绝大多数都是Linux。以下步骤在Ubuntu 20.04 LTS及更新版本上测试通过。首先更新现有的软件包列表并安装一些必要的工具这些工具允许apt通过HTTPS使用仓库sudo apt-get update sudo apt-get install ca-certificates curl gnupg lsb-release接下来添加Docker的官方GPG密钥和稳定版仓库。这一步是为了确保我们下载的软件包来自可信源并且能接收到后续的安全更新。# 创建用于存储密钥的目录 sudo mkdir -p /etc/apt/keyrings # 下载并导入Docker的GPG密钥 curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg # 添加Docker的APT仓库 echo \ deb [arch$(dpkg --print-architecture) signed-by/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable | sudo tee /etc/apt/sources.list.d/docker.list /dev/null注意$(lsb_release -cs)会自动获取你的Ubuntu发行版代号如focal、jammy。确保Docker支持你的发行版。如果遇到问题可以去Docker官网查看支持的版本列表。更新包索引并安装Docker引擎、命令行工具CLI以及容器运行时接口ContainerDsudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin安装完成后启动Docker服务并设置开机自启sudo systemctl start docker sudo systemctl enable docker最后也是最关键的一步将当前用户添加到docker用户组。这是因为Docker守护进程默认以root权限运行而docker命令需要通过Unix socket与守护进程通信该socket默认由root用户和docker用户组拥有。sudo usermod -aG docker $USER执行此命令后你需要完全退出当前终端会话并重新登录或者新开一个终端用户组变更才会生效。之后你就可以不用sudo直接运行docker命令了。验证安装是否成功docker --version docker run hello-world如果看到Docker版本信息并且hello-world镜像能成功运行并输出欢迎信息说明安装一切正常。3.2 在macOS上安装Docker Desktop对于macOS用户官方推荐使用Docker Desktop。它是一个集成了Docker引擎、CLI、Compose和图形化界面的应用程序。访问Docker官网前往 Docker Hub 的下载页面选择适用于MacIntel芯片或Apple芯片的Docker Desktop安装包。下载并安装双击下载的.dmg文件将Docker图标拖拽到“应用程序”文件夹中。首次运行从“应用程序”启动Docker Desktop。首次启动需要一些时间来完成初始化并会请求系统权限如访问网络、创建虚拟化环境。验证启动完成后可以在顶部菜单栏看到Docker的鲸鱼图标。打开终端输入docker --version和docker run hello-world进行验证。关键点Docker Desktop for Mac实际上是在macOS上运行了一个轻量级的Linux虚拟机对于Apple Silicon芯片是Linux ARM64虚拟机所有的容器都运行在这个虚拟机内。这对于用户是透明的但当你需要挂载本地目录到容器时-v参数需要理解路径是相对于这个虚拟机环境的。通常/Users目录会被自动共享进去。3.3 在Windows上安装Docker DesktopWindows上的安装与macOS类似但依赖于Windows的Hyper-V或WSL 2Windows Subsystem for Linux 2后端。前提条件对于Windows 10/11专业版、企业版或教育版建议使用WSL 2后端。需要先启用“适用于Linux的Windows子系统”和“虚拟机平台”功能然后安装一个WSL发行版如Ubuntu。对于Windows 10家庭版旧版本可能需要启用Hyper-V但Docker Desktop新版强烈推荐并支持WSL 2后端即使家庭版也能获得更好的体验。安装步骤从Docker官网下载Docker Desktop for Windows安装程序。运行安装程序安装过程中通常会提示启用WSL 2或Hyper-V按照提示操作即可。安装完成后重启电脑。启动Docker Desktop同样在系统托盘区会有图标。首次启动同样需要初始化。在PowerShell或CMD中运行docker --version和docker run hello-world验证。选择WSL 2后端的好处性能远超传统的Hyper-V文件I/O速度更快并且能实现与本地Windows文件系统的无缝集成资源消耗也更低。在Docker Desktop的设置中可以轻松切换后端。4. 配置国内镜像加速器从Docker Hub拉取镜像对于国内用户来说速度可能很慢甚至经常超时。配置一个国内的镜像加速器是安装后的首要优化步骤。这相当于为Docker换了一个离你更近的下载源。以阿里云镜像加速器为例其他如腾讯云、网易云、中科大等也提供类似服务注册并登录阿里云容器镜像服务控制台。在左侧菜单找到“镜像工具” - “镜像加速器”。你会看到一个专属于你的加速器地址格式如https://xxxx.mirror.aliyuncs.com。配置方法根据操作系统不同Linux (Ubuntu/CentOS等) 编辑Docker守护进程的配置文件/etc/docker/daemon.json如果文件不存在则新建{ registry-mirrors: [https://xxxx.mirror.aliyuncs.com] }保存后重启Docker服务使配置生效sudo systemctl daemon-reload sudo systemctl restart dockermacOS / Windows (Docker Desktop)点击系统托盘区的Docker图标选择“Settings”设置或“Preferences”偏好设置。找到“Docker Engine”选项。在配置JSON中添加或修改registry-mirrors字段填入你的加速器地址。点击“Apply Restart”应用并重启。配置完成后使用docker info命令在输出信息中查找Registry Mirrors确认加速器地址已生效。之后拉取镜像的速度会有显著提升。5. Docker生命周期管理从创建到销毁的常用命令掌握了安装和基础配置我们进入最核心的部分命令。我将按照一个容器的完整生命周期来组织这些命令这样更容易理解和记忆。5.1 镜像相关操作镜像是一切的起点。搜索镜像docker search 镜像名用于在Docker Hub上搜索公开的镜像。例如docker search nginx。不过更常见的做法是直接去Docker Hub网站查看信息更全。拉取镜像docker pull 镜像名[:标签]从仓库下载镜像到本地。如果不指定标签默认拉取latest标签。强烈建议生产环境指定具体版本标签如docker pull nginx:1.23-alpine。alpine版本基于极简的Alpine Linux镜像体积非常小。列出本地镜像docker images或docker image ls查看所有已下载的镜像包括仓库名、标签、镜像ID、创建时间和大小。删除本地镜像docker rmi 镜像ID或镜像名:标签或docker image rm ...删除不再需要的镜像以释放磁盘空间。如果镜像有对应的容器存在即使已停止需要先删除容器才能删除镜像。使用-f参数可以强制删除。查看镜像历史docker history 镜像名查看镜像的构建历史即每一层的内容和大小对于理解镜像构成和优化很有帮助。导出/导入镜像docker save和docker load用于离线环境迁移镜像。docker save -o nginx.tar nginx:alpine将镜像保存为tar文件。docker load -i nginx.tar从tar文件加载镜像。5.2 容器运行与管理这是最频繁的操作集合。运行容器docker run [选项] 镜像名 [命令]这是最核心的命令。它从镜像创建并启动一个新容器。选项非常多常用的有-d后台运行守护进程模式。-it交互式运行通常一起使用分配一个伪终端并保持标准输入打开用于进入容器内部操作如docker run -it ubuntu bash。--name为容器指定一个自定义名称否则Docker会分配一个随机名字。-p端口映射格式-p 宿主机端口:容器端口如-p 8080:80将容器的80端口映射到宿主机的8080端口。-v挂载数据卷格式-v 宿主机目录:容器目录用于持久化数据或共享配置文件。-e设置环境变量如-e MYSQL_ROOT_PASSWORDmy-secret-pw。--restart设置重启策略如--restartalways确保容器退出时总是重启非常适合运行服务。示例运行一个Nginx容器后台运行命名并映射端口。docker run -d --name my-nginx -p 80:80 nginx:alpine列出容器docker ps [选项]docker ps列出正在运行的容器。docker ps -a列出所有容器包括已停止的。 输出信息包括容器ID、名称、使用的镜像、状态、端口映射等。停止/启动/重启容器docker stop 容器名或ID优雅地停止运行中的容器发送SIGTERM信号。docker start 容器名或ID启动一个已停止的容器。docker restart 容器名或ID重启容器。进入运行中的容器docker exec [选项] 容器名或ID 命令这是与运行中容器交互的关键命令。常用-it选项启动一个交互式shell。docker exec -it my-nginx /bin/sh # alpine镜像通常用sh docker exec -it my-nginx bash # Ubuntu等完整镜像用bash注意docker attach也可以附着到容器但它连接的是容器的主进程PID 1的输入输出。如果主进程是shellattach进去后退出shell会导致容器停止。而docker exec是新建一个进程退出不会影响容器主进程。绝大多数情况下应使用docker exec。查看容器日志docker logs [选项] 容器名或ID查看容器的标准输出STDOUT和错误输出STDERR是排查问题最重要的工具之一。-f实时跟踪日志输出类似tail -f。--tail N仅显示最后N行日志。-t显示时间戳。查看容器内进程docker top 容器名或ID查看容器内部运行的进程列表。查看容器详细信息docker inspect 容器名或ID以JSON格式返回容器的底层详细信息包括配置、网络设置、挂载卷、状态等。信息非常全面用于深度调试。复制文件docker cp从容器复制到主机docker cp 容器名:容器内路径 主机路径从主机复制到容器docker cp 主机路径 容器名:容器内路径用于在容器和宿主机之间传输文件适合临时操作。对于需要频繁同步的数据应使用数据卷-v。删除容器docker rm 容器名或ID删除已停止的容器。加-f参数可以强制删除运行中的容器先发送SIGKILL。警告删除容器会丢失容器层所有未持久化的数据。5.3 数据持久化数据卷与挂载容器本身是易失的数据卷Volume是Docker中持久化数据的首选机制。它完全由Docker管理独立于容器的生命周期。创建数据卷docker volume create 卷名列出数据卷docker volume ls查看数据卷详情docker volume inspect 卷名删除未使用的数据卷docker volume prune谨慎操作在运行容器时使用-v或--mount参数挂载数据卷。--mount语法更明确推荐使用。# 使用 -v (旧式但更简洁) docker run -d --name mysql-db \ -v mysql_data:/var/lib/mysql \ # ‘mysql_data’是卷名自动创建 -e MYSQL_ROOT_PASSWORDsecret \ mysql:8.0 # 使用 --mount (新式语法更清晰) docker run -d --name mysql-db \ --mount typevolume,srcmysql_data,dst/var/lib/mysql \ -e MYSQL_ROOT_PASSWORDsecret \ mysql:8.0除了卷挂载typevolume还可以进行绑定挂载typebind直接挂载宿主机目录和临时文件系统挂载typetmpfs。5.4 网络管理Docker提供了多种网络模式默认会创建bridge、host、none等网络。列出网络docker network ls创建网络docker network create 网络名可以指定子网、网关等。查看网络详情docker network inspect 网络名将容器连接到网络docker network connect 网络名 容器名断开容器与网络的连接docker network disconnect 网络名 容器名在docker run时可以使用--network参数指定网络。创建自定义的bridge网络可以实现容器间通过容器名进行DNS解析自动服务发现这对于多容器应用如Web应用连接数据库非常方便。# 1. 创建一个自定义网络 docker network create my-app-network # 2. 运行数据库容器加入该网络 docker run -d --name mysql --network my-app-network -e MYSQL_ROOT_PASSWORDsecret mysql:8.0 # 3. 运行Web应用容器加入同一网络。Web应用可以直接用‘mysql’这个主机名连接到数据库容器。 docker run -d --name webapp --network my-app-network -p 8080:80 my-webapp-image6. 组合应用Docker Compose入门当你的应用需要多个容器协同工作时例如一个Web应用需要Nginx、Node.js、Redis和PostgreSQL手动用docker run一个个启动和管理会非常繁琐。Docker Compose就是用来定义和运行多容器Docker应用的工具。它使用一个YAML文件默认名docker-compose.yml来配置所有服务。安装在Linux上如果你按照我之前的方法安装了docker-compose-plugin那么Compose V2已经作为Docker CLI的一个插件docker compose可用。命令是docker compose注意中间没有横线。在macOS和Windows的Docker Desktop中它已内置。一个典型的docker-compose.yml示例定义一个WordPress应用包含WordPress和MySQLversion: 3.8 # 指定Compose文件格式版本 services: db: image: mysql:8.0 volumes: - db_data:/var/lib/mysql restart: always environment: MYSQL_ROOT_PASSWORD: somewordpress MYSQL_DATABASE: wordpress MYSQL_USER: wordpress MYSQL_PASSWORD: wordpress wordpress: depends_on: - db image: wordpress:latest ports: - 8000:80 restart: always environment: WORDPRESS_DB_HOST: db:3306 # 使用服务名‘db’作为主机名 WORDPRESS_DB_USER: wordpress WORDPRESS_DB_PASSWORD: wordpress WORDPRESS_DB_NAME: wordpress volumes: - wp_data:/var/www/html volumes: db_data: wp_data:常用Compose命令docker compose up启动所有服务。加-d在后台运行。docker compose down停止并移除所有容器、网络。加-v会同时删除在Compose文件中声明的数据卷危险操作。docker compose ps列出项目中的所有容器。docker compose logs [服务名]查看服务的日志。加-f跟踪输出。docker compose exec 服务名 命令在运行中的服务容器内执行命令。docker compose build根据Dockerfile重新构建服务的镜像。Compose极大地简化了多容器环境的部署和管理是本地开发和测试复杂应用的利器也常用于简单的生产部署。7. 镜像构建基石理解Dockerfile虽然从仓库拉取镜像很方便但更多时候我们需要构建自己的镜像将应用打包进去。这就需要编写Dockerfile。Dockerfile是一个文本文件包含了一系列构建镜像所需的指令。一个简单的Node.js应用Dockerfile示例# 第一阶段构建阶段 FROM node:18-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci --onlyproduction # 仅安装生产依赖 # 第二阶段运行阶段 FROM node:18-alpine WORKDIR /app # 从构建阶段复制已安装的node_modules COPY --frombuilder /app/node_modules ./node_modules # 复制应用源码 COPY . . # 声明容器运行时监听的端口 EXPOSE 3000 # 定义容器启动时执行的命令 CMD [node, server.js]常用指令解析FROM指定基础镜像所有构建都基于此。选择合适且小的基础镜像如alpine变体是优化镜像体积的第一步。WORKDIR设置工作目录后续的RUN、COPY等命令都会在此目录下执行。COPY将文件或目录从构建上下文复制到镜像中。COPY . .是把当前目录所有文件复制到镜像的/app目录。RUN在构建过程中执行命令常用于安装软件包、编译代码等。多个RUN命令应尽量合并并用连接以减少镜像层数。每一条指令都会创建一个新的镜像层。EXPOSE声明容器运行时监听的端口这是一个文档性质的指令实际映射端口仍需在docker run时用-p指定。CMD指定容器启动时默认执行的命令。一个Dockerfile中只能有一条CMD指令。它有三种格式推荐使用exec格式CMD [executable, param1, param2]。构建镜像在Dockerfile所在目录执行docker build -t 镜像名:标签 .。最后的.表示构建上下文路径。多阶段构建如上例所示它允许你在一个Dockerfile中使用多个FROM指令。你可以用一个包含完整构建工具如编译器的“构建阶段”镜像来编译代码然后将编译好的产物复制到另一个更精简的“运行阶段”镜像中。这能显著减小最终镜像的体积并提高安全性因为运行环境不包含构建工具。8. 实战中的经验、技巧与避坑指南最后这部分是我在多年使用Docker过程中积累的一些“血泪教训”和实用技巧这些在官方文档里不一定会强调。1. 容器内应用日志应输出到标准输出STDOUT/STDERRDocker的最佳实践是将应用日志直接打印到控制台而不是写入容器内的文件。这样你就可以用docker logs命令统一查看和管理日志。对于像Nginx、MySQL这类默认写日志文件的软件通常可以通过配置将其重定向到标准输出。例如Nginx可以修改配置将access log和error log指向/dev/stdout和/dev/stderr。2. 谨慎使用docker commit虽然docker commit可以将一个运行中的容器保存为镜像但这是一种“黑盒”操作无法追溯镜像的构建历史不利于维护和复现。构建镜像的标准方式永远是编写Dockerfile然后使用docker build。docker commit仅适用于临时性的调试或实验。3. 理解容器与宿主机的时间同步问题容器默认使用UTC时间且与宿主机共享时钟。但如果宿主机时间不正确或者你需要在容器内使用特定的时区可以在运行容器时设置环境变量-e TZAsia/Shanghai。对于基于Alpine的镜像可能还需要安装tzdata包。4. 清理无用资源释放磁盘空间Docker用久了会积累很多停止的容器、无用的镜像none标签的中间层镜像、未使用的数据卷和网络占用大量磁盘空间。定期清理是个好习惯。docker system prune一键清理所有已停止的容器、未被任何容器使用的网络、悬空镜像none和构建缓存。加-a会清理所有未被容器使用的镜像慎用。加--volumes会一并清理未使用的数据卷非常危险确保数据已备份。更精确的控制分别使用docker container prune,docker image prune,docker volume prune,docker network prune。5. 容器内文件权限问题当使用-v挂载宿主机目录到容器时可能会遇到容器内应用没有权限读写挂载目录的问题。这是因为容器内进程的用户UID/GID与宿主机文件的所有者不匹配。解决方法有两种一是调整宿主机目录的权限chmod或chown二是在运行容器时使用-u参数指定容器内进程的用户ID使其与宿主机目录所有者一致例如-u $(id -u):$(id -g)。6. 不要在生产环境容器中运行SSH服务有些过时的教程会教你在容器里安装SSH然后远程登录进去管理。这是一个反模式。容器的哲学是“一个容器一个进程”。你需要进入容器时应该使用docker exec。如果需要调试或查看文件可以用docker cp复制出来。在容器内运行额外服务会增加攻击面和安全风险。7. 关注镜像安全尽量使用官方镜像Docker Hub上带有“Official Image”标志的并选择具体版本号而不是latest。定期更新镜像以获取安全补丁。可以使用docker scan 镜像名命令需登录Docker Hub对本地镜像进行安全漏洞扫描。对于自己构建的镜像也应遵循最小化原则只安装必要的包。
返回列表