尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Ubuntu 20.04 Docker安装配置与容器化实践指南

Ubuntu 20.04 Docker安装配置与容器化实践指南 1. 项目概述为什么要在Ubuntu 20.04上拥抱Docker如果你是一名在Ubuntu 20.04上折腾的开发或运维大概率遇到过“环境依赖地狱”项目A需要Python 3.8项目B却死死依赖Python 3.6一个微服务需要特定版本的Redis另一个则要求完全不同的配置。更别提那些因为系统库版本差异在测试环境跑得好好的一到生产就崩掉的尴尬场景。Docker的出现正是为了解决这些痛点。它通过容器化技术将应用及其所有依赖打包成一个标准化的单元实现了“一次构建处处运行”的梦想。Ubuntu 20.04 LTSFocal Fossa作为一个长期支持版本以其稳定性和广泛的社区支持成为了众多服务器和开发机的首选系统。在这个系统上部署Docker意味着你能在一个成熟、可靠的基础设施上构建起灵活、高效的现代化应用交付流水线。无论是想快速搭建一个MySQL测试实例还是部署一个复杂的微服务架构Docker都能让你像搭积木一样轻松。今天我就以一个过来人的身份带你从零开始在Ubuntu 20.04上把Docker装好、配好、用起来并分享那些官方文档里不会写的实操细节和避坑指南。2. 核心思路与准备工作知其然更知其所以然在动手敲命令之前我们先理清几个关键概念和准备工作这能让你在后续遇到问题时知道从哪里着手排查而不是盲目地复制粘贴。2.1 Docker的核心组件与Ubuntu适配性解析很多人以为Docker就是一个命令工具其实它是一套引擎。在Ubuntu上我们主要与以下组件打交道Docker EngineDocker守护进程这是核心一个常驻后台的进程dockerd负责管理容器、镜像、网络和存储卷。我们通过客户端命令行工具与它交互。Docker Client命令行工具我们常用的docker命令就是客户端它通过REST API与守护进程通信。Docker Registry镜像仓库比如Docker Hub是存储和分发Docker镜像的地方。默认从Docker Hub拉取但在国内直接访问速度堪忧所以配置国内镜像加速是必选项。为什么选择在Ubuntu 20.04上通过APT仓库安装而不是下载二进制包原因在于依赖管理和自动更新。APTAdvanced Package Tool是Ubuntu的包管理器它能自动处理Docker运行所需的所有库依赖如containerd.io,docker-ce-cli并且未来可以通过sudo apt upgrade一键更新Docker到新版本省心又安全。相比之下二进制包安装需要手动处理依赖和更新路径更适合无法使用包管理器的特殊环境。2.2 安装前的系统检查与必要配置安装前的检查就像手术前的体检能避免很多“手术中”的意外。请依次执行以下命令# 1. 检查系统版本确认是Ubuntu 20.04 lsb_release -a你应该看到类似Description: Ubuntu 20.04.x LTS的输出。# 2. 更新现有软件包列表确保获取最新的仓库信息 sudo apt update # 3. 安装一些基础工具后续会用到 sudo apt install -y apt-transport-https ca-certificates curl software-properties-common gnupg lsb-release这里解释一下这几个包的作用apt-transport-https允许APT通过HTTPS协议访问仓库更安全ca-certificates是CA根证书用于验证HTTPS连接curl用于从网络下载software-properties-common提供了管理软件源的工具gnupg用于处理GPG密钥验证软件包签名。# 4. 关键步骤检查内核版本与虚拟化支持 uname -rDocker需要Linux内核版本在3.10以上Ubuntu 20.04默认的内核5.4完全满足。更关键的是虚拟化支持尤其是如果你后续想运行非Linux系统的容器通过qemu或者使用Docker Desktop的某些高级功能。不过对于标准的Linux容器以下检查更为重要# 检查cgroups和命名空间支持这是容器的基石 grep -E cgroup|namespace /proc/self/mountinfo如果能看到cgroup、cgroup2、namespace相关的挂载信息说明系统基础支持是完好的。很多人在虚拟机上安装失败问题往往出在这里。注意如果你是在虚拟机如VMware、VirtualBox或云服务器上操作请务必在宿主机的BIOS/UEFI设置中以及虚拟机软件配置里开启CPU的虚拟化支持Intel VT-x / AMD-V。对于物理机如果kvm-ok命令提示不支持也需要进入BIOS开启。这是很多“Docker启动失败”问题的根源。3. 分步安装与配置实战准备工作就绪现在开始正式的安装流程。我会详细解释每一步的目的让你不仅会操作还明白为什么这么做。3.1 添加Docker官方APT仓库为什么不直接用Ubuntu自带的docker.io包因为那个版本通常很旧是Docker早期开源版本的一个分支现在叫moby缺少很多新特性和安全更新。我们要安装的是Docker官方维护的社区版Docker CE。# 1. 添加Docker的官方GPG密钥 # 这一步是为了验证从Docker仓库下载的软件包是真实且未被篡改的。 curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg这里用了管道符|将curl下载的密钥直接传递给gpg命令处理。-fsSL参数让curl在失败时静默退出、跟随重定向、显示错误、并以列表形式输出是安全的下载习惯。--dearmor是将ASCII格式的密钥转换为二进制格式。# 2. 设置稳定版stable仓库 # 这里我们明确指定了Ubuntu 20.04 (focal)的amd64架构仓库。 echo \ deb [arch$(dpkg --print-architecture) signed-by/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable | sudo tee /etc/apt/sources.list.d/docker.list /dev/nullarch$(dpkg --print-architecture)会自动获取你的系统架构如amd64, arm64。signed-by指向我们刚刚导入的GPG密钥文件确保来源可信。$(lsb_release -cs)会输出你的Ubuntu代号对于20.04就是focal。tee命令将内容同时输出到屏幕和文件 /dev/null将屏幕输出丢弃保持终端整洁。3.2 安装Docker Engine及相关组件添加仓库后就可以安装了。# 1. 再次更新APT包索引使新增的Docker仓库生效 sudo apt update # 2. 安装Docker Engine、命令行工具以及Containerd sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugindocker-ce: Docker社区版引擎。docker-ce-cli: Docker命令行工具。containerd.io: 行业标准的容器运行时Docker Engine底层依赖它来管理容器生命周期。docker-compose-plugin: 这是Docker Compose V2作为一个CLI插件安装。旧式的docker-composePython编写已不再推荐这个插件版本性能更好集成度更高。安装过程会自动创建docker用户组并将Docker守护进程设置为开机自启。3.3 安装后的关键配置与验证安装完成只是第一步正确的配置才能让它好用又安全。1. 管理用户权限避免每次都sudo默认情况下执行docker命令需要root权限即加sudo。为了方便可以将当前用户加入docker用户组。# 将当前用户加入docker组 sudo usermod -aG docker $USER重要提醒执行此命令后必须完全注销当前会话并重新登录或者重启系统用户组变更才会生效。仅仅新开一个终端标签页是不够的。这是新手最常忽略的一点会导致执行docker ps时依然报权限错误。2. 配置国内镜像加速器从Docker Hub拉取镜像速度慢且不稳定。配置国内镜像加速是提升体验的关键。这里以阿里云镜像加速为例需要注册阿里云账号获取专属地址。# 创建或修改Docker守护进程的配置文件 sudo tee /etc/docker/daemon.json -EOF { registry-mirrors: [https://your_mirror_url.mirror.aliyuncs.com], exec-opts: [native.cgroupdriversystemd], log-driver: json-file, log-opts: { max-size: 100m }, storage-driver: overlay2 } EOFregistry-mirrors: 将your_mirror_url替换为你从阿里云容器镜像服务控制台获取的专属加速器地址。也可以添加多个如中科大、网易的镜像源。exec-opts: 设置cgroup驱动为systemd这与Ubuntu 20.04默认使用systemd作为初始化系统保持一致能获得更好的稳定性。log-driver和log-opts: 配置日志驱动和单个日志文件最大尺寸防止日志撑爆磁盘。storage-driver: 存储驱动overlay2是当前推荐且性能较好的驱动适用于Ubuntu 20.04的ext4或xfs文件系统。3. 重启Docker服务并验证应用配置后需要重启服务。# 重新加载systemd配置重启Docker服务 sudo systemctl daemon-reload sudo systemctl restart docker # 设置Docker服务开机自启 sudo systemctl enable docker # 运行一个测试容器验证安装和配置是否成功 docker run --rm hello-world如果一切顺利你将看到一段“Hello from Docker!”的欢迎信息并说明你的安装看起来工作正常。这个命令会从配置的镜像加速器拉取hello-world镜像创建并运行一个容器输出信息后自动删除容器--rm参数作用。4. Docker基础使用与核心概念实操安装配置妥当我们来真正“用”起来。理解下面几个核心操作你就能应对80%的日常场景。4.1 镜像Image操作应用的模板镜像是只读的模板包含了运行应用所需的代码、运行时、库、环境变量和配置文件。可以把它理解成面向对象编程中的“类”。# 搜索镜像例如搜索Ubuntu镜像 docker search ubuntu # 拉取镜像从仓库下载到本地。不指定标签则默认为latest。 docker pull ubuntu:20.04 docker pull nginx:alpine # 拉取更轻量的nginx alpine版本 # 列出本地已下载的镜像 docker images # 或者使用更强大的格式 docker image ls --format table {{.Repository}}\t{{.Tag}}\t{{.ID}}\t{{.CreatedAt}}\t{{.Size}} # 删除本地镜像 docker rmi image_id或image_name:tag # 强制删除即使有容器基于它 docker rmi -f image_id # 清理所有未被使用的镜像悬空镜像 docker image prune4.2 容器Container操作镜像的运行实例容器是镜像的可运行实例。你可以创建、启动、停止、移动或删除容器。它是“类”的“对象”。# 1. 运行一个新容器 # -d: 后台运行 # --name: 给容器起个名字方便管理 # -p: 端口映射将宿主机的8080端口映射到容器的80端口 docker run -d --name my-nginx -p 8080:80 nginx:alpine # 2. 查看容器状态 docker ps # 查看运行中的容器 docker ps -a # 查看所有容器包括已停止的 # 3. 与容器交互 # 查看容器日志 docker logs my-nginx # 实时查看日志类似 tail -f docker logs -f my-nginx # 进入正在运行的容器内部执行命令打开一个交互式终端 docker exec -it my-nginx /bin/sh # 退出容器终端输入 exit 或按 CtrlD # 4. 容器的生命周期管理 docker stop my-nginx # 停止容器 docker start my-nginx # 启动已停止的容器 docker restart my-nginx # 重启容器 # 5. 删除容器 docker rm my-nginx # 删除已停止的容器 docker rm -f my-nginx # 强制删除运行中的容器4.3 数据持久化与网络让容器更实用默认情况下容器内创建的文件只在容器生命周期内存在容器删除数据就没了。网络方面容器有独立的网络命名空间。数据卷Volume是持久化容器数据的首选机制完全由Docker管理与宿主机生命周期解耦。# 创建一个名为my-data的数据卷 docker volume create my-data # 运行一个容器并将数据卷挂载到容器内的/app/data目录 docker run -d --name my-app -v my-data:/app/data some-image # 查看所有数据卷 docker volume ls # 查看数据卷详情如挂载点 docker volume inspect my-data # 删除未使用的数据卷 docker volume prune绑定挂载Bind Mount将宿主机上的一个特定目录或文件挂载到容器中。适合开发时同步代码。# 将宿主机的/home/user/project目录挂载到容器的/code目录 docker run -d -v /home/user/project:/code some-dev-image网络Network默认情况下Docker会创建三种网络bridge默认、host、none。你可以创建自定义网络让容器间通过容器名通信。# 创建一个自定义的桥接网络 docker network create my-network # 运行两个容器并加入同一个自定义网络 docker run -d --name web --network my-network nginx docker run -it --name client --network my-network alpine ping web # 在client容器内可以直接ping通web这个主机名5. 使用Docker Compose编排多容器应用当你的应用需要多个容器协同工作时比如一个Web应用需要Web服务器、数据库、缓存手动管理每个容器非常繁琐。Docker Compose就是用来定义和运行多容器Docker应用的工具。我们安装的是V2插件版本命令是docker compose注意中间没有横线。5.1 编写docker-compose.yml文件在一个项目目录下创建一个名为docker-compose.yml的文件。下面是一个经典的WordPress MySQL的编排示例version: 3.8 # 指定Compose文件格式版本 services: # 数据库服务 db: image: mysql:8.0 # 使用MySQL 8.0镜像 container_name: wordpress_db restart: always # 总是重启保证服务可用性 environment: # 设置环境变量这里是数据库的root密码和创建的数据库名、用户 MYSQL_ROOT_PASSWORD: your_strong_root_password MYSQL_DATABASE: wordpress MYSQL_USER: wordpress MYSQL_PASSWORD: your_wordpress_db_password volumes: - db_data:/var/lib/mysql # 使用命名卷持久化数据库数据 networks: - wp-network # WordPress服务 wordpress: image: wordpress:latest container_name: wordpress_app restart: always depends_on: # 依赖关系确保db服务先启动 - db ports: - 8080:80 # 将宿主机的8080端口映射到容器的80端口 environment: WORDPRESS_DB_HOST: db:3306 # 这里直接用服务名dbCompose网络会自动解析 WORDPRESS_DB_USER: wordpress WORDPRESS_DB_PASSWORD: your_wordpress_db_password WORDPRESS_DB_NAME: wordpress volumes: - wp_data:/var/www/html # 持久化WordPress网站文件 networks: - wp-network # 定义数据卷供上面的服务使用 volumes: db_data: wp_data: # 定义网络让两个服务在同一个隔离网络中通信 networks: wp-network: driver: bridge5.2 使用Compose命令管理应用在包含docker-compose.yml文件的目录下执行以下命令# 1. 启动所有服务在后台运行 docker compose up -d # 2. 查看当前目录下Compose应用的状态 docker compose ps # 3. 查看服务的日志可以指定服务名如db docker compose logs docker compose logs -f wordpress # 实时跟踪wordpress服务的日志 # 4. 停止并移除所有容器、网络默认不会移除数据卷 docker compose down # 5. 停止并移除所有容器、网络同时移除数据卷数据会丢失 docker compose down -v # 6. 在运行中的服务上执行命令例如进入db容器的bash docker compose exec db bash通过Compose你用一个YAML文件和几条简单的命令就管理起了一个完整的多服务应用栈极大地简化了部署复杂度。6. 常见问题排查与性能优化心得即使按照步骤操作你也可能会遇到一些问题。这里记录了几个我踩过的坑和解决方案。6.1 Docker服务启动失败与权限问题问题现象执行sudo systemctl status docker发现服务状态不是active (running)或者执行docker ps时提示Cannot connect to the Docker daemon。排查思路检查服务状态与日志sudo systemctl status docker sudo journalctl -xu docker --no-pager -n 50 # 查看Docker服务的详细日志日志是定位问题的第一手资料。常见错误包括iptables相关错误可能是防火墙规则冲突。可以尝试暂时禁用ufw(sudo ufw disable) 或调整Docker的iptables配置。cgroup挂载错误检查/proc/self/mountinfo中是否有cgroup相关条目。确保系统已正确启用cgroup。存储驱动错误如果日志提到overlay2和xfs相关错误可能是文件系统不支持d_type。用xfs_info /检查ftype是否为1。如果不是可能需要重新格式化分区。检查用户组权限 如果你已经将用户加入docker组但仍然需要sudo请确认你是否已经重新登录了会话。可以运行groups命令查看当前用户所属组是否包含docker。也可以直接测试docker run --rm hello-world如果不加sudo能运行说明权限正确。检查端口冲突 如果Docker能启动但运行容器时端口映射失败如Error starting userland proxy: listen tcp4 0.0.0.0:8080: bind: address already in use说明宿主机8080端口已被占用。使用sudo netstat -tulpn | grep :8080查找占用进程并停止它或者为容器映射另一个端口。6.2 镜像拉取缓慢或失败问题现象docker pull速度极慢或出现net/http: TLS handshake timeout等超时错误。解决方案确认镜像加速器配置正确检查/etc/docker/daemon.json文件中的registry-mirrors地址是否有效且格式正确JSON格式要求严格最后一个项后不能有逗号。修改后务必执行sudo systemctl restart docker。使用多个镜像源可以在registry-mirrors数组中配置多个地址Docker会依次尝试。registry-mirrors: [ https://hub-mirror.c.163.com, https://mirror.baidubce.com, https://docker.mirrors.ustc.edu.cn ]直接使用国内镜像仓库对于一些常用镜像如ubuntu,nginx,mysql可以直接从阿里云、腾讯云的镜像仓库拉取例如docker pull registry.cn-hangzhou.aliyuncs.com/library/ubuntu:20.04。6.3 容器磁盘空间占用过大问题现象运行一段时间后/var/lib/docker目录Docker默认数据根目录体积暴涨导致系统磁盘空间不足。清理策略 Docker占用的空间主要包括未使用的镜像、停止的容器、构建缓存、数据卷。定期清理是必要的。# 1. 查看Docker磁盘使用概况 docker system df # 2. 一键清理所有未使用的资源镜像、容器、网络、构建缓存但**不清理数据卷**。 docker system prune -a # 3. 谨慎清理数据卷会丢失数据 docker volume prune # 4. 清理所有停止的容器 docker container prune # 5. 清理所有悬空镜像未被任何容器引用的镜像 docker image prune实操心得建议将docker system prune加入定时任务如cron每周执行一次但务必注意生产环境避免误删正在使用的中间镜像或缓存。对于数据卷清理前一定要确认其数据是否已备份或可丢弃。6.4 容器内应用时区不对问题现象在容器内运行date命令显示的是UTC时间而不是东八区北京时间。解决方案在运行容器时将宿主机的时区文件挂载到容器内。docker run -d --name some-app \ -v /etc/localtime:/etc/localtime:ro \ -v /etc/timezone:/etc/timezone:ro \ your-image或者在构建自己的Docker镜像时在Dockerfile中设置时区环境变量FROM ubuntu:20.04 RUN apt-get update apt-get install -y tzdata ENV TZAsia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime echo $TZ /etc/timezone7. 进阶使用构建自定义镜像与Dockerfile编写拉取现成镜像只是开始更多时候我们需要定制自己的镜像。Dockerfile是一个文本文件包含了一条条构建镜像所需的指令。7.1 一个完整的Dockerfile示例假设我们要为一个简单的Python Flask应用构建镜像。# 第一阶段构建阶段使用较大的基础镜像包含构建工具 FROM python:3.9-slim as builder WORKDIR /app # 将依赖文件复制到工作目录 COPY requirements.txt . # 使用清华PyPI镜像加速安装依赖到/usr/local RUN pip install --no-cache-dir -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt # 第二阶段运行阶段使用更小的基础镜像 FROM python:3.9-alpine # 设置时区 RUN apk add --no-cache tzdata \ cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ echo Asia/Shanghai /etc/timezone \ apk del tzdata WORKDIR /app # 从构建阶段仅复制安装好的Python包 COPY --frombuilder /usr/local/lib/python3.9/site-packages /usr/local/lib/python3.9/site-packages COPY --frombuilder /usr/local/bin /usr/local/bin # 复制应用代码 COPY . . # 声明容器运行时监听的端口 EXPOSE 5000 # 设置环境变量指定Flask应用入口 ENV FLASK_APPapp.py ENV FLASK_RUN_HOST0.0.0.0 # 定义容器启动时执行的命令 CMD [flask, run]7.2 构建与运行自定义镜像在包含Dockerfile和app.py、requirements.txt的目录下执行# 构建镜像-t 参数给镜像打标签格式为 name:tag docker build -t my-flask-app:1.0 . # 查看构建好的镜像 docker images | grep my-flask-app # 运行容器 docker run -d -p 5000:5000 --name my-flask-container my-flask-app:1.07.3 Dockerfile编写最佳实践与心得使用多阶段构建如上例所示可以显著减小最终镜像体积。第一阶段安装编译依赖、构建代码第二阶段只复制构建产物到一个小体积的基础镜像中。合理利用构建缓存Docker会缓存每一层。把变化频率低的指令如安装系统包、依赖放在Dockerfile前面把变化频率高的指令如复制源代码放在后面。使用.dockerignore文件类似于.gitignore可以避免将本地不必要的文件如__pycache__,.git,.env复制到镜像构建上下文中加速构建过程并避免泄露敏感信息。一个容器只运行一个进程这是微服务的最佳实践。如果需要运行多个关联进程如Web服务器和后台Worker应考虑使用Supervisor等进程管理工具或者更好的方式是拆分为多个容器用Docker Compose编排。以非root用户运行容器在Dockerfile中创建并使用一个非root用户增强安全性。RUN groupadd -r appuser useradd -r -g appuser appuser USER appuser标签Tag管理为镜像使用有意义的标签如版本号v1.2.3、Git提交哈希git-abc123避免过度依赖latest标签这有助于回滚和追踪问题。在Ubuntu 20.04上搭建好Docker环境并掌握了这些核心操作和问题排查技巧后你就拥有了一个强大且一致的开发、测试和部署环境。无论是个人项目还是团队协作容器化都能极大地提升效率和可靠性。记住关键不在于记住所有命令而在于理解其背后的原理镜像、容器、数据卷、网络这样无论遇到什么新工具或复杂场景你都能从容应对。
返回列表