一、Docker 大致介绍
Docker 可以帮助我们完成应用的 运行(run) 、构建(build) 和 分享(share)。
它的核心目标很简单:
- 把应用和环境打包起来
- 让应用在不同机器上尽量保持一致
- 方便部署、迁移和分发
二、Docker 的几个核心概念
1. Docker Host
首先,我们需要一台 VPS,在这台 VPS 上安装 Docker。
这台装了 Docker 环境的 VPS,通常叫做:
text
Docker Host
也就是 Docker 主机。
2. Docker Daemon
Docker Daemon 是 Docker 的守护进程。
它会一直运行,负责接收命令并处理容器、镜像等操作。
3. Docker CLI
Docker CLI 是命令行工具,也就是我们平时输入的 docker 命令。
比如:
bash
docker pull redis
这个命令就是由 Docker CLI 发给 Docker Daemon 去执行。
4. Registry
Registry 可以理解成镜像仓库,也就是 Docker 的应用市场。
里面有很多常见镜像,比如:
- MySQL
- Nginx
- Redis
这些镜像可以直接下载使用。
5. Image 和 Container
- Image(镜像):可以理解成应用模板
- Container(容器):镜像运行起来后的实例
镜像是静态的,容器是运行中的。
三、Docker 的基本工作流程
1. 拉取镜像
bash
docker pull redis
这个命令的意思是:
- Docker Daemon 接收到命令
- 去 Registry 找
redis镜像 - 下载到本地
2. 运行容器
bash
docker run redis
这个命令的意思是:
- 先看本地有没有
redis镜像 - 如果没有,就去 Registry 下载
- 然后用这个镜像启动一个 Redis 容器
3. 多个容器
同一个镜像可以启动多个容器。
比如你可以同时启动多个 Redis 容器,每个容器都是独立隔离的。
四、Docker 能做什么
Docker 最常见的用途就是这三件事:
1. Run:运行应用
把镜像变成正在运行的容器。
2. Build:构建镜像
bash
docker build xxx
这个命令可以用来制作自己的镜像。
3. Share:分享镜像
bash
docker push xxx
这个命令可以把自己做好的镜像推送到 Registry,方便别人下载和使用。
五、简单理解 Docker 的关系
可以这样记:
- Docker Host:安装了 Docker 的机器
- Docker Daemon:后台守护进程,负责干活
- Docker CLI:我们输入命令的地方
- Registry:镜像仓库,存放镜像
- Image:镜像,应用模板
- Container:容器,镜像运行后的实例
六、Docker 的安装
在 VPS 中可以直接执行官方安装脚本:
bash
curl -fsSL https://get.docker.com | bash
官方文档:
text
https://docs.docker.com/engine/install/ubuntu/
七、Docker 无法连接时的配置
如果 Docker 无法连接,可以创建这个文件:
bash
/etc/docker/daemon.json
在里面可以配置:
- Docker 数据目录
- Registry 镜像加速
- 本地代理
示例配置
json
{
"data-root": "/data/docker",
"registry-mirrors": [
"https://docker.1ms.run"
],
"proxies": {
"http-proxy": "http://127.0.0.1:7890",
"https-proxy": "http://127.0.0.1:7890",
"no-proxy": "localhost,127.0.0.1"
}
}
1. data-root
data-root 是 Docker 的数据根目录。
镜像、容器、卷等持久化数据默认都放在这里。
Linux 默认值是:
text
/var/lib/docker
如果你想把 Docker 数据放到别的盘,可以修改这个值,比如:
json
"data-root": "/data/docker"
2. registry-mirrors
这个配置是镜像加速地址。
常见用途是加速拉取镜像。
如果已经配置了可用的国内镜像,很多情况下就不需要再额外配代理了。
3. proxies
这个配置是代理。
适合本机无法直接访问外网镜像仓库的情况。
八、代理和镜像的简单理解
一般来说:
- 国外机器通常只需要配置
data-root - 国内机器通常会配置
data-root+ 代理 - 也可以直接配置国内镜像加速
一个常见场景
A:国内 VPS
- 安装 Docker
- 需要拉外网镜像
B:国外 VPS
- 安装 Tinyproxy
- 作为 HTTP 正向代理
A 机器的 Docker daemon
- 在
daemon.json里把代理指向 B
这样 A 就能通过 B 去拉镜像。
九、在国外 VPS 上安装 Tinyproxy
在国外 VPS 上可以这样安装:
bash
sudo apt update
sudo apt install -y tinyproxy
安装完成后,Tinyproxy 可以作为 HTTP 正向代理使用。
十、国外服务器 B:Tinyproxy 完整配置
/etc/tinyproxy/tinyproxy.conf
conf
User nobody
Group nogroup
Port 8888
Timeout 600
Listen 0.0.0.0
Allow 1.2.3.4
BasicAuth dockerproxy StrongPass123
Syslog On
LogLevel Info
# 不写 ConnectPort 表示允许 CONNECT 到所有目标端口
# 如果以后想收紧,只允许标准 HTTPS,可以取消下面这一行注释
# ConnectPort 443
配置说明
User nobody/Group nogroup:Tinyproxy 的运行身份,按机器实际存在的用户组来写Port 8888:代理监听端口Timeout 600:连接空闲超时Listen 0.0.0.0:监听全部网卡Allow 1.2.3.4:只允许国内 A 机公网 IP 访问BasicAuth dockerproxy StrongPass123:代理认证Syslog On:日志输出到 syslogLogLevel Info:日志级别ConnectPort 443:如果启用,只允许 CONNECT 到 443 端口
十一、Docker daemon 的代理配置示例
json
{
"data-root": "/data/docker",
"registry-mirrors": [
"https://your-mirror.example.com"
],
"proxies": {
"http-proxy": "http://dockerproxy:StrongPass123@203.0.113.10:8888",
"https-proxy": "http://dockerproxy:StrongPass123@203.0.113.10:8888",
"no-proxy": "localhost,127.0.0.1,.local"
}
}
说明
- 如果已经配置了可用的国内镜像,很多情况下就不需要再额外配代理了
- 如果还是需要访问外网镜像仓库,就可以继续保留代理配置
no-proxy里写本机地址和局域网域名,避免这些地址走代理
十二、国内服务器通过 systemd 给 Docker 配代理
国内服务器还可以通过 systemd 单独给 Docker 服务配代理。
配置文件
bash
/etc/systemd/system/docker.service.d/http-proxy.conf
内容
ini
[Service]
Environment="HTTP_PROXY=http://dockerproxy:StrongPass123@203.0.113.10:8888"
Environment="HTTPS_PROXY=http://dockerproxy:StrongPass123@203.0.113.10:8888"
Environment="NO_PROXY=localhost,127.0.0.1,.local"
说明
这样 Docker 服务启动之后,就默认使用这个代理。
修改完以后,执行:
bash
sudo systemctl daemon-reload
sudo systemctl restart docker
额外说明
- 修改了
/etc/docker/daemon.json后,只需要执行:
bash
sudo systemctl restart docker
- 修改了
/etc/systemd/system/docker.service.d/http-proxy.conf后,需要先执行:
bash
sudo systemctl daemon-reload
sudo systemctl restart docker
十三、Docker 常用命令
Docker 的基础环境和运行原理了解之后,就可以开始学常用命令了。
下面这些是最常用的一批命令。
1. docker search
搜索镜像。
bash
docker search redis
2. docker pull
从镜像仓库拉取镜像。
bash
docker pull redis
docker pull 的完整写法
docker pull 的本质是:
text
镜像名:标签
比如:
bash
docker pull nginx
实际上等价于:
bash
docker pull nginx:latest
因为不写标签时,默认就是 latest。
如果你拉取了 nginx,再用:
bash
docker images
就能看到本地已经有这个镜像了。
下载指定版本镜像
如果你想下载指定版本,就直接在镜像名后面加标签,比如:
bash
docker pull nginx:1.26.0
这表示下载 nginx 的 1.26.0 版本。
3. docker images
查看本地有哪些镜像。
bash
docker images
4. docker ps
查看正在运行的容器。
bash
docker ps
docker ps 是查看正在运行中的容器。
5. docker ps -a
查看所有容器,包括已经停止的。
bash
docker ps -a
docker ps -a 是查看正在运行 + 已停止 的所有容器。
6. docker run
运行一个容器。
bash
docker run redis
7. docker stop
停止一个正在运行的容器。
bash
docker stop 容器ID
8. docker start
启动一个已经停止的容器。
bash
docker start 容器ID
已停止的容器,可以通过 docker start 再次运行。
9. docker restart
重启容器。
bash
docker restart 容器ID
已经运行的容器,可以通过 docker restart 重新运行。
10. docker rm
删除容器。
bash
docker rm 容器ID
删除容器时,容器必须已经停止。
你也可以使用:
bash
docker rm -f 容器ID
这个方式可以强制删除正在运行中的容器。
11. docker rmi
删除镜像。
bash
docker rmi 镜像ID
12. docker logs
查看容器日志。
bash
docker logs 容器ID
13. docker exec
进入正在运行的容器执行命令。
bash
docker exec -it 容器ID bash
14. docker inspect
查看容器或镜像的详细信息。
bash
docker inspect 容器ID
15. docker build
构建镜像。
bash
docker build -t myapp:1.0 .
16. docker push
推送镜像到仓库。
bash
docker push myapp:1.0
17. docker stats
查看容器资源使用情况。
bash
docker stats
十四、镜像和容器命令补充说明
前面这一节已经把最常用的镜像和容器命令列出来了,这里做一个简单归类:
镜像相关
docker searchdocker pulldocker imagesdocker rmidocker builddocker commitdocker savedocker loaddocker logindocker tagdocker push
容器相关
docker rundocker psdocker ps -adocker stopdocker startdocker restartdocker rmdocker logsdocker execdocker inspectdocker stats
一些常见组合
bash
docker ps -aq
docker rm -f $(docker ps -aq)
bash
docker commit -m "修改了Nginx首页" mynginx myNginx:v1.0
bash
docker save -o nginx.tar nginx:1.26.0
bash
docker load -i nginx.tar
十五、保存镜像的几个命令
十五、保存镜像的几个命令
1. docker commit
把正在运行的容器保存成一个新的镜像。
bash
docker commit -m "修改了Nginx首页" mynginx myNginx:v1.0
这个命令的意思是:
-m:提交说明mynginx:容器名myNginx:v1.0:新的镜像名和版本
执行完 docker commit -m "修改了Nginx首页" mynginx myNginx:v1.0 之后,再执行:
bash
docker images
就可以看到你自己的镜像了。
2. docker save
把镜像保存成一个文件。
bash
docker save -o nginx.tar nginx:1.26.0
docker save -o 后面写导出的 .tar 文件名,再写镜像名和版本,就可以把镜像导出成 xxx.tar。
这个 xxx.tar 可以用 scp 传输给其他机子。
3. docker load
把保存好的镜像文件重新加载回来。
bash
docker load -i nginx.tar
执行完 docker load -i xxx.tar 后,再执行:
bash
docker images
就可以看到有这个镜像了。
十六、Docker 镜像分享社区
Docker 镜像分享到社区时,通常会用到这三个命令:
1. docker login
登录镜像仓库。
默认登录的是 Docker Hub。
如果是个人 Harbor,也可以登录你的 Harbor 仓库地址。
2. docker tag
给本地镜像打标签,改成仓库地址格式。
3. docker push
把镜像推送到仓库。
个人 Harbor 的完整流程
假设你的 Harbor 地址是 harbor.example.com,完整流程一般是这样:
bash
docker login harbor.example.com
然后给镜像打标签:
bash
docker tag mynginx:v1.0 harbor.example.com/library/mynginx:v1.0
最后推送:
bash
docker push harbor.example.com/library/mynginx:v1.0
如果是 Docker Hub,流程也类似,只是仓库地址会换成 Docker Hub 的命名方式。
docker tag 为什么需要
docker tag 是因为推送的镜像需要满足仓库的命名要求。
也就是说,先把本地镜像改成"仓库地址 + 项目名 + 版本号"的格式,docker push 才知道推到哪里。
十七、Docker 命令速记图
text
镜像
- docker search
- docker pull
- docker images
- docker rmi
容器
- docker run
- docker ps
- docker stop
- docker start
- docker restart
- docker stats
- docker logs
- docker exec
- docker rm
分享
- docker commit
- docker save
- docker load
- docker login
- docker tag
- docker push
十八、一个小技巧
docker ps -aq
-a:打印所有容器-q:只打印容器 ID
所以:
bash
docker ps -aq
表示打印所有容器的 ID,包括运行中的和停止的。
删除所有容器
bash
docker rm -f $(docker ps -aq)
这个命令的意思是:
docker ps -aq先拿到所有容器 IDdocker rm -f再强制删除这些容器
所以它可以删除所有运行中的和停止的容器。
十九、Docker 存储:目录挂载和卷映射
Docker 的存储方式,常见有两种:
- 目录挂载
- 卷映射
1. 目录挂载
目录挂载可以用 -v 把宿主机目录映射到容器里。
例如:
bash
docker run -v ./data:/data nginx
或者使用绝对路径:
bash
docker run -v /data/app:/data nginx
目录挂载的意思是:
- 宿主机上的文件夹
- 映射到 Docker 容器内
目录挂载适合什么情况
如果这些文件是 容器运行之后生成的,目录挂载就很合适。
比如:
- 日志文件
- 上传文件
- 数据文件
- 容器运行后才生成的配置文件
目录挂载的问题
如果这些文件是 容器一开始就需要存在的,目录挂载就可能有问题。
因为:
- 容器里原本有内容
- 但宿主机挂进去的是空目录
- 结果把容器里的原始内容覆盖掉了
除非你在宿主机上提前把这些文件准备好,否则目录挂载可能会对容器产生严重影响。
2. 卷映射
卷映射可以解决这个问题。
它适合:
- 容器需要持久化数据
- 不想直接依赖宿主机具体路径
- 想让 Docker 自己管理数据
卷映射的默认位置
卷映射默认会放在 Docker 的数据根目录下面。
如果没有改过配置,默认是在:
text
/var/lib/docker/volumes/<volume-name>/_data
如果你在 /etc/docker/daemon.json 里配置了:
json
"data-root": "/data/docker"
那么卷映射的数据位置也会跟着变到:
text
/data/docker/volumes/<volume-name>/_data
也就是说,data-root 会影响 Docker 整体数据存放位置,卷映射的位置也会一起改变。
目录挂载和卷映射的写法
目录挂载
目录挂载是把宿主机目录映射到容器目录。
写法通常是:
bash
docker run -v /app/nghtml:/usr/share/nginx/html nginx
如果使用相对路径,也可以这样写:
bash
docker run -v ./data:/data nginx
目录挂载要注意区分:
- 绝对路径写法 :
/app/nghtml:/usr/share/nginx/html - 相对路径写法 :
./data:/data
卷映射
卷映射也是用 -v,但左边通常不是你自己指定的宿主机目录,而是 Docker 管理的卷名。
例如:
bash
docker run -v ngconf:/etc/nginx nginx
宿主机变化会不会影响容器
无论是目录挂载还是卷映射,宿主机里的内容变化,都会反映到容器内部。
也就是说:
- 宿主机改了文件,容器里会看到变化
- 容器里改了文件,宿主机里也会看到变化
这就是挂载和卷映射的意义:让宿主机和容器共享同一份数据
目录挂载和卷映射的区别
目录挂载
- 你自己指定宿主机路径
- 比如
/app/nghtml或./data - 适合自己明确知道文件放哪的场景
卷映射
- Docker 自己管理路径
- 默认在 Docker 数据目录下的
_data里 - 更适合长期持久化数据
目录挂载的场景示例
比如 Nginx 日志,容器启动后会不断生成新文件,这种场景适合目录挂载:
bash
docker run -v /data/nginx/logs:/var/log/nginx nginx
一开始就需要存在的文件
比如某些应用启动时必须读取配置文件,如果容器里本来就有默认配置,而宿主机挂进去的是空目录,就会出问题。这个时候更适合先把宿主机文件准备好,或者改用卷映射。
二十、Docker 网络
Docker 默认会有一个 docker0 网络。
为什么需要自定义 Docker 网络
假设有两个容器:
app1app2
宿主机端口映射如下:
app1:宿主机 88 端口映射到容器内部 80app2:宿主机 99 端口映射到容器内部 80
如果使用 Docker 默认网络,那么容器内部的 app1 想访问 app2,通常要先访问宿主机地址:
bash
curl http://宿主机IP:99
这就很绕,明明两个容器就在同一台机器里,却非要先绕到宿主机端口再访问。
可以把它理解成:
同事就在你旁边,你却先跑到公司门口,再重新进来找他聊天。
很绕,也很不自然。
docker0 是 Docker 的默认网络
docker0 是 Docker 默认网络。
你可以通过下面的命令查看容器的详细信息:
bash
docker container inspect xxx
里面会看到容器在 docker0 网络中的 IP 地址,比如:
text
172.17.0.2
这个 IP 就是容器在 docker0 网络中的地址。
直接用容器 IP 访问的问题
你可以通过容器 IP 来访问另一个容器,但有一个问题:
- 容器启动顺序不同,IP 可能变化
- 容器重启后,IP 也可能变化
所以直接用容器 IP 不够稳定。
容器名和内部 IP 的访问方式
容器名访问比直接写 IP 更好一些。
因为容器名更容易记,也更稳定。
为什么要自定义 Docker 网络
Docker 默认的 docker0 网络,通常不适合直接用容器名互相访问。
如果你想让容器之间直接通过:
- 容器名
- 内部 IP
来访问,就需要在运行容器时把它们加入一个自定义网络。
这样容器之间就可以直接互相通信,不需要先绕到宿主机端口。
创建和使用自定义网络
先创建一个自定义网络:
bash
docker network create mynet
然后把容器加入这个网络:
bash
docker run --network mynet --name app1 nginx
docker run --network mynet --name app2 redis
这样 app1 就可以直接通过容器名访问 app2:
bash
curl http://app2:6379
二十一、最简单的总结
Docker 的安装和基础配置可以先记住这几件事:
- 安装:
curl -fsSL https://get.docker.com | bash - 配置文件:
/etc/docker/daemon.json data-root:Docker 数据目录registry-mirrors:镜像加速proxies:代理配置- Tinyproxy:可以作为国外 VPS 的 HTTP 正向代理出口
- 也可以通过 systemd 给 Docker 服务单独配置代理
如果你先把这些搞明白,Docker 的入门就算通了。