Docker 快速通关
一、Docker 大致介绍
Docker 可以帮助我们完成应用的运行(run)、构建(build)和分享(share)。
它的核心目标很简单:
- 把应用和环境打包起来
- 让应用在不同机器上尽量保持一致
- 方便部署、迁移和分发
二、Docker 的几个核心概念
1. Docker Host
首先,我们需要一台 VPS,在这台 VPS 上安装 Docker。
这台装了 Docker 环境的 VPS,通常叫做:
Docker Host也就是 Docker 主机。
2. Docker Daemon
Docker Daemon 是 Docker 的守护进程。
它会一直运行,负责接收命令并处理容器、镜像等操作。
3. Docker CLI
Docker CLI 是命令行工具,也就是我们平时输入的docker命令。
比如:
dockerpull redis这个命令就是由 Docker CLI 发给 Docker Daemon 去执行。
4. Registry
Registry 可以理解成镜像仓库,也就是 Docker 的应用市场。
里面有很多常见镜像,比如:
- MySQL
- Nginx
- Redis
这些镜像可以直接下载使用。
5. Image 和 Container
- Image(镜像):可以理解成应用模板
- Container(容器):镜像运行起来后的实例
镜像是静态的,容器是运行中的。
三、Docker 的基本工作流程
1. 拉取镜像
dockerpull redis这个命令的意思是:
- Docker Daemon 接收到命令
- 去 Registry 找
redis镜像 - 下载到本地
2. 运行容器
dockerrun redis这个命令的意思是:
- 先看本地有没有
redis镜像 - 如果没有,就去 Registry 下载
- 然后用这个镜像启动一个 Redis 容器
3. 多个容器
同一个镜像可以启动多个容器。
比如你可以同时启动多个 Redis 容器,每个容器都是独立隔离的。
四、Docker 能做什么
Docker 最常见的用途就是这三件事:
1. Run:运行应用
把镜像变成正在运行的容器。
2. Build:构建镜像
dockerbuild xxx这个命令可以用来制作自己的镜像。
3. Share:分享镜像
dockerpush xxx这个命令可以把自己做好的镜像推送到 Registry,方便别人下载和使用。
五、简单理解 Docker 的关系
可以这样记:
- Docker Host:安装了 Docker 的机器
- Docker Daemon:后台守护进程,负责干活
- Docker CLI:我们输入命令的地方
- Registry:镜像仓库,存放镜像
- Image:镜像,应用模板
- Container:容器,镜像运行后的实例
六、Docker 的安装
在 VPS 中可以直接执行官方安装脚本:
curl-fsSLhttps://get.docker.com|bash官方文档:
https://docs.docker.com/engine/install/ubuntu/七、Docker 无法连接时的配置
如果 Docker 无法连接,可以创建这个文件:
/etc/docker/daemon.json在里面可以配置:
- Docker 数据目录
- Registry 镜像加速
- 本地代理
示例配置
{"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 默认值是:
/var/lib/docker如果你想把 Docker 数据放到别的盘,可以修改这个值,比如:
"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 上可以这样安装:
sudoaptupdatesudoaptinstall-ytinyproxy安装完成后,Tinyproxy 可以作为 HTTP 正向代理使用。
十、国外服务器 B:Tinyproxy 完整配置
/etc/tinyproxy/tinyproxy.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 的代理配置示例
{"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 服务配代理。
配置文件
/etc/systemd/system/docker.service.d/http-proxy.conf内容
[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 服务启动之后,就默认使用这个代理。
修改完以后,执行:
sudosystemctl daemon-reloadsudosystemctl restartdocker额外说明
- 修改了
/etc/docker/daemon.json后,只需要执行:
sudosystemctl restartdocker- 修改了
/etc/systemd/system/docker.service.d/http-proxy.conf后,需要先执行:
sudosystemctl daemon-reloadsudosystemctl restartdocker十三、Docker 常用命令
Docker 的基础环境和运行原理了解之后,就可以开始学常用命令了。
下面这些是最常用的一批命令。
1.docker search
搜索镜像。
dockersearch redis2.docker pull
从镜像仓库拉取镜像。
dockerpull redisdocker pull的完整写法
docker pull的本质是:
镜像名:标签比如:
dockerpull nginx实际上等价于:
dockerpull nginx:latest因为不写标签时,默认就是latest。
如果你拉取了nginx,再用:
dockerimages就能看到本地已经有这个镜像了。
下载指定版本镜像
如果你想下载指定版本,就直接在镜像名后面加标签,比如:
dockerpull nginx:1.26.0这表示下载nginx的1.26.0版本。
3.docker images
查看本地有哪些镜像。
dockerimages4.docker ps
查看正在运行的容器。
dockerpsdocker ps是查看正在运行中的容器。
5.docker ps -a
查看所有容器,包括已经停止的。
dockerps-adocker ps -a是查看正在运行 + 已停止的所有容器。
6.docker run
运行一个容器。
dockerrun redis7.docker stop
停止一个正在运行的容器。
dockerstop 容器ID8.docker start
启动一个已经停止的容器。
dockerstart 容器ID已停止的容器,可以通过docker start再次运行。
9.docker restart
重启容器。
dockerrestart 容器ID已经运行的容器,可以通过docker restart重新运行。
10.docker rm
删除容器。
dockerrm容器ID删除容器时,容器必须已经停止。
你也可以使用:
dockerrm-f容器ID这个方式可以强制删除正在运行中的容器。
11.docker rmi
删除镜像。
dockerrmi 镜像ID12.docker logs
查看容器日志。
dockerlogs 容器ID13.docker exec
进入正在运行的容器执行命令。
dockerexec-it容器IDbash14.docker inspect
查看容器或镜像的详细信息。
dockerinspect 容器ID15.docker build
构建镜像。
dockerbuild-tmyapp:1.0.16.docker push
推送镜像到仓库。
dockerpush myapp:1.017.docker stats
查看容器资源使用情况。
dockerstats十四、镜像和容器命令补充说明
前面这一节已经把最常用的镜像和容器命令列出来了,这里做一个简单归类:
镜像相关
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
一些常见组合
dockerps-aqdockerrm-f$(dockerps-aq)dockercommit-m"修改了Nginx首页"mynginx myNginx:v1.0dockersave-onginx.tar nginx:1.26.0dockerload-inginx.tar十五、保存镜像的几个命令
十五、保存镜像的几个命令
1.docker commit
把正在运行的容器保存成一个新的镜像。
dockercommit-m"修改了Nginx首页"mynginx myNginx:v1.0这个命令的意思是:
-m:提交说明mynginx:容器名myNginx:v1.0:新的镜像名和版本
执行完docker commit -m "修改了Nginx首页" mynginx myNginx:v1.0之后,再执行:
dockerimages就可以看到你自己的镜像了。
2.docker save
把镜像保存成一个文件。
dockersave-onginx.tar nginx:1.26.0docker save -o后面写导出的.tar文件名,再写镜像名和版本,就可以把镜像导出成xxx.tar。
这个xxx.tar可以用scp传输给其他机子。
3.docker load
把保存好的镜像文件重新加载回来。
dockerload-inginx.tar执行完docker load -i xxx.tar后,再执行:
dockerimages就可以看到有这个镜像了。
十六、Docker 镜像分享社区
Docker 镜像分享到社区时,通常会用到这三个命令:
1.docker login
登录镜像仓库。
默认登录的是 Docker Hub。
如果是个人 Harbor,也可以登录你的 Harbor 仓库地址。
2.docker tag
给本地镜像打标签,改成仓库地址格式。
3.docker push
把镜像推送到仓库。
个人 Harbor 的完整流程
假设你的 Harbor 地址是harbor.example.com,完整流程一般是这样:
dockerlogin harbor.example.com然后给镜像打标签:
dockertag mynginx:v1.0 harbor.example.com/library/mynginx:v1.0最后推送:
dockerpush harbor.example.com/library/mynginx:v1.0如果是 Docker Hub,流程也类似,只是仓库地址会换成 Docker Hub 的命名方式。
docker tag为什么需要
docker tag是因为推送的镜像需要满足仓库的命名要求。
也就是说,先把本地镜像改成“仓库地址 + 项目名 + 版本号”的格式,docker push才知道推到哪里。
十七、Docker 命令速记图
镜像 - 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
所以:
dockerps-aq表示打印所有容器的 ID,包括运行中的和停止的。
删除所有容器
dockerrm-f$(dockerps-aq)这个命令的意思是:
docker ps -aq先拿到所有容器 IDdocker rm -f再强制删除这些容器
所以它可以删除所有运行中的和停止的容器。
十九、Docker 存储:目录挂载和卷映射
Docker 的存储方式,常见有两种:
- 目录挂载
- 卷映射
1. 目录挂载
目录挂载可以用-v把宿主机目录映射到容器里。
例如:
dockerrun-v./data:/data nginx或者使用绝对路径:
dockerrun-v/data/app:/data nginx目录挂载的意思是:
- 宿主机上的文件夹
- 映射到 Docker 容器内
目录挂载适合什么情况
如果这些文件是容器运行之后生成的,目录挂载就很合适。
比如:
- 日志文件
- 上传文件
- 数据文件
- 容器运行后才生成的配置文件
目录挂载的问题
如果这些文件是容器一开始就需要存在的,目录挂载就可能有问题。
因为:
- 容器里原本有内容
- 但宿主机挂进去的是空目录
- 结果把容器里的原始内容覆盖掉了
除非你在宿主机上提前把这些文件准备好,否则目录挂载可能会对容器产生严重影响。
2. 卷映射
卷映射可以解决这个问题。
它适合:
- 容器需要持久化数据
- 不想直接依赖宿主机具体路径
- 想让 Docker 自己管理数据
卷映射的默认位置
卷映射默认会放在 Docker 的数据根目录下面。
如果没有改过配置,默认是在:
/var/lib/docker/volumes/<volume-name>/_data如果你在/etc/docker/daemon.json里配置了:
"data-root":"/data/docker"那么卷映射的数据位置也会跟着变到:
/data/docker/volumes/<volume-name>/_data也就是说,data-root会影响 Docker 整体数据存放位置,卷映射的位置也会一起改变。
目录挂载和卷映射的写法
目录挂载
目录挂载是把宿主机目录映射到容器目录。
写法通常是:
dockerrun-v/app/nghtml:/usr/share/nginx/html nginx如果使用相对路径,也可以这样写:
dockerrun-v./data:/data nginx目录挂载要注意区分:
- 绝对路径写法:
/app/nghtml:/usr/share/nginx/html - 相对路径写法:
./data:/data
卷映射
卷映射也是用-v,但左边通常不是你自己指定的宿主机目录,而是 Docker 管理的卷名。
例如:
dockerrun-vngconf:/etc/nginx nginx宿主机变化会不会影响容器
无论是目录挂载还是卷映射,宿主机里的内容变化,都会反映到容器内部。
也就是说:
- 宿主机改了文件,容器里会看到变化
- 容器里改了文件,宿主机里也会看到变化
这就是挂载和卷映射的意义:让宿主机和容器共享同一份数据
目录挂载和卷映射的区别
目录挂载
- 你自己指定宿主机路径
- 比如
/app/nghtml或./data - 适合自己明确知道文件放哪的场景
卷映射
- Docker 自己管理路径
- 默认在 Docker 数据目录下的
_data里 - 更适合长期持久化数据
目录挂载的场景示例
比如 Nginx 日志,容器启动后会不断生成新文件,这种场景适合目录挂载:
dockerrun-v/data/nginx/logs:/var/log/nginx nginx一开始就需要存在的文件
比如某些应用启动时必须读取配置文件,如果容器里本来就有默认配置,而宿主机挂进去的是空目录,就会出问题。这个时候更适合先把宿主机文件准备好,或者改用卷映射。
二十、Docker 网络
Docker 默认会有一个docker0网络。
为什么需要自定义 Docker 网络
假设有两个容器:
app1app2
宿主机端口映射如下:
app1:宿主机 88 端口映射到容器内部 80app2:宿主机 99 端口映射到容器内部 80
如果使用 Docker 默认网络,那么容器内部的app1想访问app2,通常要先访问宿主机地址:
curlhttp://宿主机IP:99这就很绕,明明两个容器就在同一台机器里,却非要先绕到宿主机端口再访问。
可以把它理解成:
同事就在你旁边,你却先跑到公司门口,再重新进来找他聊天。
很绕,也很不自然。
docker0 是 Docker 的默认网络
docker0是 Docker 默认网络。
你可以通过下面的命令查看容器的详细信息:
dockercontainer inspect xxx里面会看到容器在docker0网络中的 IP 地址,比如:
172.17.0.2这个 IP 就是容器在docker0网络中的地址。
直接用容器 IP 访问的问题
你可以通过容器 IP 来访问另一个容器,但有一个问题:
- 容器启动顺序不同,IP 可能变化
- 容器重启后,IP 也可能变化
所以直接用容器 IP 不够稳定。
容器名和内部 IP 的访问方式
容器名访问比直接写 IP 更好一些。
因为容器名更容易记,也更稳定。
为什么要自定义 Docker 网络
Docker 默认的docker0网络,通常不适合直接用容器名互相访问。
如果你想让容器之间直接通过:
- 容器名
- 内部 IP
来访问,就需要在运行容器时把它们加入一个自定义网络。
这样容器之间就可以直接互相通信,不需要先绕到宿主机端口。
创建和使用自定义网络
先创建一个自定义网络:
dockernetwork create mynet然后把容器加入这个网络:
dockerrun--networkmynet--nameapp1 nginxdockerrun--networkmynet--nameapp2 redis这样app1就可以直接通过容器名访问app2:
curlhttp://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 的入门就算通了。
