从零上手:在Linux虚拟机里点亮你的第一个容器
从零上手:在Linux虚拟机里点亮你的第一个容器
你是否也曾被“环境依赖”问题折磨?代码在本地运行良好,一到服务器就各种报错。今天,我将带你在RHEL9虚拟机上,通过实际动手操作,点亮你的第一个容器,亲身体验这项革命性技术如何解决这一痛点。
为什么需要容器技术?
在传统部署方式中,应用直接运行在物理机或虚拟机上,需要与底层操作系统共享库、配置文件等环境依赖。这就导致了经典的“在我电脑上能运行”的问题。
容器技术通过操作系统级别的虚拟化,将应用及其所有依赖打包在一个独立的运行时环境中。想象一下集装箱运输:
-
标准化:无论在何处,集装箱内的货物都受到同样保护
-
隔离性:一个集装箱的问题不会影响其他集装箱
-
便携性:可在任何支持集装箱的船舶、卡车间运输
容器正是软件世界的“集装箱”。
环境准备
1. 安装RHEL9虚拟机
我们首先需要准备一个干净的Linux环境。如果你已经有Linux环境,可以跳过这一步。
我推荐使用VirtualBox或VMware创建虚拟机:
-
分配至少2GB内存、20GB硬盘空间
-
安装介质选择RHEL9 ISO文件
-
在安装过程中,确保勾选“Server with GUI”或“Minimal Install”并开启网络连接
2. 系统基础配置
安装完成后,登录系统并执行以下基础配置:
bash
# 切换到root用户(或使用sudo) sudo -i # 更新系统 dnf update -y # 安装必要的工具 dnf install -y vim wget curl net-tools # 设置主机名 hostnamectl set-hostname container-lab
3. 配置SSH远程连接(可选但推荐)
为方便操作,可以配置SSH服务:
bash
# 启动SSH服务 systemctl enable --now sshd # 查看IP地址 ip addr show # 配置防火墙允许SSH firewall-cmd --permanent --add-service=ssh firewall-cmd --reload
现在可以从宿主机通过SSH连接到虚拟机,复制粘贴命令会更方便。
安装容器运行时
在RHEL9中,我们使用Podman作为容器运行时。Podman是Red Hat推出的Daemonless容器引擎,与Docker命令行高度兼容但无需守护进程。
1. 启用容器模块
bash
# 启用容器模块 dnf module enable -y container-tools # 安装Podman dnf install -y podman # 验证安装 podman --version
你应该看到类似 podman version 4.x.x 的输出,表示安装成功。
2. 配置非root用户运行容器(重要安全实践)
默认情况下,Podman需要root权限运行容器。我们可以配置非root用户的容器环境:
bash
# 为普通用户配置子UID和子GID(假设你的用户名是student) sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 student # 验证配置 grep student /etc/subuid grep student /etc/subgid
注意:配置完成后需要重新登录才能生效。
运行第一个容器
现在让我们开始容器探险之旅!
1. 拉取第一个镜像
bash
# 搜索可用的容器镜像 podman search nginx # 拉取Nginx官方镜像 podman pull docker.io/library/nginx:alpine # 查看已下载的镜像 podman images
alpine 标签表示这是基于Alpine Linux的轻量级镜像,体积小,非常适合学习使用。
2. 运行并探索容器
bash
# 以交互模式运行容器 podman run -it --name my-first-container docker.io/library/nginx:alpine /bin/sh # 你现在已经进入容器内部! # 查看容器内的进程 ps aux # 查看容器内的文件系统 ls -la / # 查看操作系统信息 cat /etc/os-release # 退出容器(容器会停止运行) exit
3. 以守护进程模式运行容器
bash
# 以后台模式运行Nginx容器 podman run -d --name web-server -p 8080:80 docker.io/library/nginx:alpine # 查看运行中的容器 podman ps # 查看容器日志 podman logs web-server # 在宿主机上访问容器服务 curl http://localhost:8080 # 进入正在运行的容器 podman exec -it web-server /bin/sh # 查看Nginx配置文件 cat /etc/nginx/nginx.conf # 退出但不停止容器(按Ctrl+P, Ctrl+Q)
深入理解容器原理
1. 容器的隔离机制
容器并非完整的虚拟机,它们与宿主机共享同一个内核,但通过Linux的命名空间和控制组实现隔离:
bash
# 查看容器的进程ID
podman inspect web-server --format '{{.State.Pid}}'
# 查看容器的命名空间信息
sudo ls -la /proc/<PID>/ns/
# 查看控制组信息
cat /proc/<PID>/cgroup
每个命名空间提供了不同的隔离环境:
-
PID命名空间:独立的进程ID空间
-
Network命名空间:独立的网络栈
-
Mount命名空间:独立的文件系统视图
-
UTS命名空间:独立的主机名和域名
2. 容器与虚拟机的对比
让我们通过一个实验直观感受两者的区别:
bash
# 1. 启动一个容器
podman run -d --name test-container docker.io/library/alpine:latest sleep 3600
# 2. 查看容器内的进程
podman exec test-container ps aux
# 3. 在宿主机查看同一个进程
CONTAINER_PID=$(podman inspect test-container --format '{{.State.Pid}}')
echo "容器内PID 1对应的宿主机PID是: $CONTAINER_PID"
ps aux | grep -E "PID|$CONTAINER_PID"
关键区别总结:
| 特性 | 容器 | 虚拟机 |
|---|---|---|
| 启动速度 | 秒级 | 分钟级 |
| 性能损耗 | 低(<5%) | 高(15-30%) |
| 隔离级别 | 进程级别 | 硬件级别 |
| 镜像大小 | MB级别 | GB级别 |
| 宿主机共享 | 共享内核 | 独立内核 |
构建自定义容器镜像
1. 创建Dockerfile
让我们创建一个简单的自定义应用并打包成容器镜像:
bash
# 创建项目目录
mkdir ~/myapp && cd ~/myapp
# 创建简单的Python应用
cat > app.py << 'EOF'
#!/usr/bin/env python3
from http.server import HTTPServer, BaseHTTPRequestHandler
import socket
class SimpleHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
hostname = socket.gethostname()
message = f"""
<html>
<body>
<h1>Hello from Container World!</h1>
<p>Server Hostname: {hostname}</p>
<p>Request Path: {self.path}</p>
<p>This is my first custom container!</p>
</body>
</html>
"""
self.wfile.write(message.encode())
if __name__ == '__main__':
server = HTTPServer(('0.0.0.0', 8080), SimpleHandler)
print('Server starting on port 8080...')
server.serve_forever()
EOF
# 创建Dockerfile
cat > Dockerfile << 'EOF'
# 使用Alpine Python作为基础镜像
FROM docker.io/library/python:3.9-alpine
# 设置工作目录
WORKDIR /app
# 复制应用文件
COPY app.py /app/
# 暴露端口
EXPOSE 8080
# 运行应用
CMD ["python3", "app.py"]
EOF
2. 构建并运行自定义镜像
bash
# 构建镜像 podman build -t my-python-app . # 查看构建的镜像 podman images | grep my-python-app # 运行自定义应用 podman run -d --name myapp -p 8888:8080 my-python-app # 测试应用 curl http://localhost:8888 # 或者用浏览器访问 firefox http://localhost:8888 &
容器网络深入探索
1. 理解容器网络模式
bash
# 查看容器网络配置
podman inspect web-server --format '{{.NetworkSettings}}' | python3 -m json.tool
# 创建自定义网络
podman network create my-network
# 在自定义网络中运行容器
podman run -d --name container1 --network my-network nginx:alpine
podman run -d --name container2 --network my-network nginx:alpine
# 测试容器间通信
podman exec container1 ping -c 3 container2
# 查看网络详情
podman network inspect my-network
2. 容器端口映射原理
端口映射是通过iptables实现的:
bash
# 查看NAT规则 sudo iptables -t nat -L -n # 查看具体的端口转发规则 sudo iptables -t nat -L PREROUTING -n -v
容器存储管理
1. 使用卷(Volume)持久化数据
bash
# 创建卷 podman volume create my-data # 运行使用卷的容器 podman run -d --name db-container \ -v my-data:/var/lib/mysql \ docker.io/library/mysql:8.0 # 查看卷信息 podman volume inspect my-data # 在宿主机查看卷数据 sudo ls -la /var/lib/containers/storage/volumes/my-data/_data
2. 绑定挂载(Bind Mount)
bash
# 创建宿主机目录 mkdir ~/web-content # 创建测试页面 echo "<h1>Hello from Bind Mount</h1>" > ~/web-content/index.html # 运行容器并绑定挂载 podman run -d --name web-with-bind \ -p 8081:80 \ -v ~/web-content:/usr/share/nginx/html:ro \ nginx:alpine # 测试 curl http://localhost:8081
容器编排初探
1. 使用Podman Compose
bash
# 安装Podman Compose
sudo dnf install -y podman-compose
# 创建docker-compose.yml
cat > docker-compose.yml << 'EOF'
version: '3'
services:
web:
image: nginx:alpine
ports:
- "8080:80"
volumes:
- ./html:/usr/share/nginx/html
db:
image: postgres:13-alpine
environment:
POSTGRES_PASSWORD: secret
volumes:
- postgres-data:/var/lib/postgresql/data
volumes:
postgres-data:
EOF
# 创建HTML目录
mkdir html
echo "<h1>Multi-Container App</h1>" > html/index.html
# 启动应用栈
podman-compose up -d
# 查看状态
podman-compose ps
# 停止应用栈
podman-compose down
最佳实践与安全建议
1. 安全准则
bash
# 1. 使用非root用户运行容器 podman run -d --name secure-app \ --user 1000:1000 \ nginx:alpine # 2. 只读文件系统(除非必要) podman run -d --name read-only-app \ --read-only \ nginx:alpine # 3. 限制资源使用 podman run -d --name limited-app \ --memory 256m \ --cpu-quota 50000 \ nginx:alpine # 查看资源限制 podman stats
2. 日常维护命令
bash
# 查看容器资源使用
podman stats
# 清理无用资源
podman system prune -a
# 更新所有镜像
podman images --format "{{.Repository}}" | xargs -L1 podman pull
# 导出/导入容器
podman export web-server > web-container.tar
podman import web-container.tar my-nginx:exported
故障排除指南
常见问题及解决方案
bash
# 问题1: 端口被占用 # 错误信息: Error: port is already allocated # 解决方案: 更改端口或停止占用端口的容器 podman run -d -p 8082:80 nginx:alpine # 问题2: 镜像拉取失败 # 错误信息: Error: error pulling image # 解决方案: 配置镜像加速器 mkdir -p ~/.config/containers cat > ~/.config/containers/registries.conf << EOF unqualified-search-registries = ["docker.io"] [[registry]] prefix = "docker.io" location = "registry-1.docker.io" [[registry.mirror]] location = "mirror.ccs.tencentyun.com" EOF # 问题3: 权限不足 # 错误信息: permission denied # 解决方案: 配置rootless模式或使用sudo sudo podman run ... # 临时解决方案 # 或正确配置subuid/subgid
学习路径建议
现在你已经点亮了第一个容器,接下来可以:
-
深入学习Dockerfile编写:掌握多阶段构建、构建优化
-
探索容器编排:学习Kubernetes基础知识
-
实践CI/CD流水线:将容器集成到自动化部署流程中
-
关注容器安全:学习镜像扫描、运行时安全
总结
通过今天的实践,我们不仅运行了第一个容器,还深入理解了:
-
容器的核心价值:环境一致性、快速部署、资源高效利用
-
Podman的基本操作:拉取镜像、运行容器、管理生命周期
-
容器底层原理:命名空间、控制组、联合文件系统
-
实际应用场景:自定义镜像构建、数据持久化、多容器编排
容器技术是云原生时代的基石。掌握它,你就打开了现代应用部署的大门。记住,最好的学习方式就是不断实践——尝试部署你自己的应用到容器中,遇到问题并解决它。
祝你在容器化的道路上越走越远!如果有任何问题,欢迎在评论区交流讨论。
更多推荐
所有评论(0)