前言

你一定听过这句话:”在我机器上能跑,怎么到你这就崩了?”

环境配置是软件开发最头疼的问题之一。不同操作系统、不同依赖版本、不同环境变量……哪怕只是一个微小的差异,都可能导致程序运行失败。

Docker就是来彻底解决这个问题的。它把应用程序和所有依赖打包成一个”容器”,在任何机器上都能保证完全一样的运行环境。

本文会带你从零开始,亲手完成Docker的安装、容器运行和应用部署,让你5分钟上手Docker。


一、Docker是什么?

简单来说,Docker就是一个应用打包工具

  • 把你的应用 + 依赖包(Python环境、Node库、数据库等)打包成一个文件
  • 这个文件可以在任何安装了Docker的机器上运行
  • 运行效果完全一致,就像在虚拟机里一样

Docker vs 虚拟机

你可能觉得”这不就是虚拟机吗?” 不,它比虚拟机轻量得多:

特性 虚拟机 Docker容器
启动速度 分钟级 秒级
资源占用 几GB内存 几十MB内存
硬盘占用 几十GB 几百MB
性能开销 高(虚拟化整个OS) 低(共享主机内核)

虚拟机是”装了一个完整的操作系统”,Docker容器是”只是隔离了应用程序进程”。所以Docker启动快、占用少、性能高。


二、安装Docker

Ubuntu/Debian系统

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 更新包索引
sudo apt-get update

# 安装依赖
sudo apt-get install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common

# 添加Docker官方GPG密钥
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

# 添加Docker仓库
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

# 安装Docker CE
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io

# 验证安装
sudo docker version

CentOS系统

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 安装依赖
sudo yum install -y yum-utils

# 添加Docker仓库
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

# 安装Docker CE
sudo yum install -y docker-ce docker-ce-cli containerd.io

# 启动Docker
sudo systemctl start docker

# 验证安装
sudo docker version

避免每次输sudo

把当前用户加入docker组,以后就不用每次都加sudo了:

1
2
3
4
sudo usermod -aG docker $USER

# 退出重新登录使生效,或者执行:
newgrp docker

三、第一个Docker容器

运行hello-world测试Docker是否正常工作:

1
docker run hello-world

你会看到这样的输出:

1
2
Hello from Docker!
This message shows that your message appears to be working correctly.

这表示:

  1. Docker从远程仓库拉取了hello-world镜像
  2. 镜像在本地创建了容器并运行
  3. 容器运行成功,输出提示信息

四、核心概念:镜像和容器

镜像(Image) = 应用的打包文件(只读)
容器(Container) = 镜像运行后的实例(可读写)

类比:

  • 镜像是”类(Class)”,容器是”对象(Object)”
  • 镜像是”安装包”,容器是”运行中的程序”

常用镜像操作

1
2
3
4
5
6
7
8
9
10
11
# 从仓库拉取镜像
docker pull nginx

# 列出本地所有镜像
docker images

# 删除镜像
docker rmi nginx

# 搜索镜像
docker search redis

常用容器操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 运行容器(-d后台运行,-p端口映射)
docker run -d -p 80:80 nginx

# 列出运行中的容器
docker ps

# 列出所有容器(包括停止的)
docker ps -a

# 停止容器
docker stop <容器ID>

# 启动已停止的容器
docker start <容器ID>

# 删除容器
docker rm <容器ID>

# 查看容器日志
docker logs <容器ID>

# 进入容器内部
docker exec -it <容器ID> /bin/bash

五、实战:部署一个Web应用

以部署Nginx Web服务器为例,演示完整流程。

步骤1:拉取Nginx镜像

1
docker pull nginx

步骤2:运行容器

1
docker run -d -p 8080:80 --name my-nginx nginx

参数解释:

  • -d:后台运行
  • -p 8080:80:把容器的80端口映射到主机8080端口
  • --name my-nginx:给容器起个名字

步骤3:验证部署

打开浏览器访问:http://你的服务器IP:8080

你会看到Nginx的欢迎页面!

步骤4:修改网页内容

先进入容器看看:

1
docker exec -it my-nginx /bin/bash

进入后你会看到类似这样的提示符:

1
2
root@abc123:/# ls /usr/share/nginx/html/
50x.html index.html

这就是Nginx的默认网页目录。修改index.html:

1
2
3
echo "<h1>Hello Docker!</h1>" > /usr/share/nginx/html/index.html

exit

刷新浏览器,页面变成”Hello Docker!”了!

步骤5:用挂载卷的方式(推荐)

上面直接修改容器文件不方便,更好的方式是把主机目录挂载到容器:

1
2
3
4
5
6
7
8
9
10
11
# 先删除刚才的容器
docker stop my-nginx
docker rm my-nginx

# 在主机上创建网页目录
mkdir -p ~/my-website

# 运行容器,挂载目录
docker run -d -p 8080:80 --name my-nginx \
-v ~/my-website:/usr/share/nginx/html \
nginx

现在编辑 ~/my-website/index.html

1
echo "<h1>我的网站</h1><p>这是用Docker部署的</p>" > ~/my-website/index.html

刷新浏览器,内容立马更新!


六、实战:部署Node.js应用

假设你有一个Node.js项目,目录结构如下:

1
2
3
4
my-app/
├── package.json
├── index.js
└── Dockerfile

步骤1:编写Dockerfile

在项目根目录创建Dockerfile文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 使用官方Node.js镜像作为基础
FROM node:14

# 设置工作目录
WORKDIR /app

# 复制package.json并安装依赖
COPY package*.json ./
RUN npm install

# 复制应用代码
COPY . .

# 暴露端口
EXPOSE 3000

# 启动应用
CMD ["node", "index.js"]

步骤2:构建镜像

1
2
cd my-app
docker build -t my-node-app .

步骤3:运行容器

1
docker run -d -p 3000:3000 my-node-app

访问 http://你的服务器IP:3000,应用就上线了!


七、常用场景速查

场景1:快速测试一个工具

想试用某个软件但不想安装?

1
2
3
4
5
6
7
8
# 测试Redis
docker run -it redis redis-cli

# 测试Python
docker run -it python:3.9 python

# 测试MySQL(设置root密码)
docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql

场景2:批量跑任务

有10个脚本要并行跑?开10个容器:

1
2
3
for i in {1..10}; do
docker run -d my-script
done

场景3:开发环境隔离

不同项目需要不同Python版本?

1
2
3
4
5
# 项目1用Python 3.7
docker run -it -v $(pwd):/app python:3.7 bash

# 项目2用Python 3.11
docker run -it -v $(pwd):/app python:3.11 bash

八、常用命令备忘录

镜像相关

1
2
3
4
docker pull <镜像名>           # 拉取镜像
docker images # 列出镜像
docker rmi <镜像ID> # 删除镜像
docker build -t <名字> . # 构建镜像

容器相关

1
2
3
4
5
6
7
8
9
docker ps                       # 列出运行中的容器
docker ps -a # 列出所有容器
docker run <参数> <镜像> # 运行容器
docker stop <容器ID> # 停止容器
docker start <容器ID> # 启动容器
docker rm <容器ID> # 删除容器
docker logs <容器ID> # 查看日志
docker exec -it <容器ID> /bin/bash # 进入容器
docker cp 本地文件 容器:/路径 # 拷贝文件到容器

清理相关

1
2
3
4
5
6
7
8
# 删除所有停止的容器
docker container prune

# 删除所有未使用的镜像
docker image prune -a

# 一键清理所有未使用的资源
docker system prune -a

九、常见问题

Q1:容器启动失败怎么办?

查看日志定位问题:

1
docker logs <容器ID>

Q2:如何查看容器占用的资源?

1
docker stats

Q3:容器里安装的软件会保留吗?

不会。容器删除后,里面的修改就没了。

持久化数据的方法:

  • 挂载目录:-v 主机路径:容器路径
  • 数据卷:-v 卷名:容器路径

Q4:国内拉取镜像很慢怎么办?

配置国内镜像源,编辑 /etc/docker/daemon.json

1
2
3
4
5
6
{
"registry-mirrors": [
"https://docker.mirrors.ustc.edu.cn",
"https://hub-mirror.c.163.com"
]
}

重启Docker:

1
sudo systemctl restart docker

Q5:Docker和Kubernetes是什么关系?

  • Docker是容器运行时(打包、运行容器)
  • Kubernetes是容器编排平台(管理成百上千个Docker容器)

类比:

  • Docker是集装箱
  • Kubernetes是集装箱码头的大吊车

十、进阶:Docker Compose

如果要同时运行多个容器(比如Web + 数据库 + Redis),一个个启动太麻烦。

Docker Compose可以一次启动多个容器,只需一个配置文件。

docker-compose.yml 示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
version: '3'
services:
web:
image: nginx
ports:
- "8080:80"
volumes:
- ./website:/usr/share/nginx/html

db:
image: mysql
environment:
MYSQL_ROOT_PASSWORD: 123456
ports:
- "3306:3306"

redis:
image: redis
ports:
- "6379:6379"

启动所有服务:

1
docker-compose up -d

停止所有服务:

1
docker-compose down

总结

Docker的核心就三个字:打包、分发、运行

  • 打包:把应用和依赖打包成镜像
  • 分发:把镜像推送到仓库,别人拉取就能用
  • 运行:在任何机器上运行容器,效果一致

掌握了Docker,你就掌握了现代应用部署的核心技能。下一步可以深入研究Docker Compose、Kubernetes、CI/CD集成等。

推荐阅读:

有问题?欢迎在评论区交流!


本文原创,转载请注明出处:洞洞博客