Docker 是一个开源的容器化平台,可以把应用和它所有的依赖打包在一起,形成一个轻量、可移植的容器,然后拿到任何 Linux 机器上都能跑。
安装 Docker
Windows / Mac
Windows 和 Mac 用户直接安装 Docker Desktop 就行,去官网下载安装包,一路下一步搞定。
Windows 额外步骤:安装 WSL2
Windows 上跑 Docker Desktop 需要 WSL2 后端。先检查系统是否满足要求——Windows 10 版本 2004 及以上,或者 Windows 11 都行。
以管理员身份打开 PowerShell 或 CMD,运行:
wsl --install
这条命令会默认安装 Ubuntu 子系统并启用 WSL2。装完后重启电脑。
如果之前装过旧版 WSL,可以手动升级到 WSL2:
wsl --set-default-version 2
重启完打开 Docker Desktop,设置里确保勾选了"Use WSL 2 based engine",它就会自动调用 WSL2 后端。
Linux
以前装 Docker 总是各种问题——源不对、依赖缺、GPG 密钥过期,折腾半天还装不上。后来发现 OnePanel 提供的这个一键脚本,是真的好用:
bash <(curl -sSL https://linuxmirrors.cn/docker.sh)
一条命令搞定,省心省力,强烈推荐。
装完之后验证一下:
docker --version
能正常输出版本号就说明安装成功了。
配置镜像加速
装完之后国内拉镜像还是慢,需要配个加速器。编辑 Docker 配置文件 daemon.json:
Linux 位置 /etc/docker/daemon.json:
{
"registry-mirrors": [
"https://docker.1ms.run"
]
}
然后重启 Docker:
sudo systemctl daemon-reload
sudo systemctl restart docker
Windows / Mac 在 Docker Desktop 里打开 Settings → Docker Engine,把上面的 JSON 粘进去,点 Apply & Restart。
我用的是 https://docker.1ms.run,目前一直挺稳的。其他的像 DaoCloud (https://docker.m.daocloud.io) 也可以试试,哪个快用哪个。
配完之后验证一下:
docker info | Select-String "Registry Mirrors"
能看到你配的地址就说明生效了。
安装过程中如果遇到什么问题,直接问 AI 基本都能解决。
镜像操作
搜索镜像
装好了先试试搜镜像:
docker search nginx
但因为 Docker Hub 被墙了,直接搜大概率搜不到。大多数梯子默认只代理浏览器的流量,PowerShell 和终端是不走代理的,所以需要在梯子里开启 TUN 模式,让整个电脑的流量都走代理,命令行才能正常访问 Docker Hub。
开了 TUN 之后再搜就能正常返回结果:
NAME DESCRIPTION STARS OFFICIAL
nginx Official build of Nginx. 21299 [OK]
nginx/nginx-ingress NGINX and NGINX Plus Ingress Controllers fo… 121
nginx/nginx-prometheus-exporter NGINX Prometheus Exporter for NGINX and NGINX… 51
linuxserver/nginx An Nginx container, brought to you by LinuxS… 236
ubuntu/nginx Nginx, a high-performance reverse proxy & we… 141
各列的意思:
- NAME — 镜像名,
nginx是官方镜像,linuxserver/nginx这种带斜杠的是个人或组织上传的 - DESCRIPTION — 镜像描述
- STARS — 星数,越高说明用的人越多
- OFFICIAL — 标了
[OK]的是 Docker 官方维护的镜像,安全性更高
拉取镜像
搜到想要的镜像之后拉下来:
docker pull nginx
docker pull 会从 Docker Hub 拉取镜像,这也是我们前面配镜像加速的原因——有了加速器,拉取速度会快不少。
拉的时候留意输出,能看到它在一层一层地下载:
Using default tag: latest
latest: Pulling from library/nginx
d98f5a0e4c6c: Pull complete
fa3c2e36864c: Pull complete
0e36bf78359e: Pull complete
Docker 镜像是由多个只读层组成的,每一层代表一个改动——比如装了一个包、复制了一个文件。这样做的好处是:不同镜像可以共用相同的层。比如你拉了 nginx 和 redis,它们可能都基于同一个基础层,本地只需要存一份,节省磁盘空间。
你可以试试先拉一个镜像,再拉另一个有相同基础层的镜像:
docker pull openjdk:11
docker pull openjdk:17
拉第二个的时候会发现有些层显示 Already exists,就因为那些层跟第一个镜像是一样的,不需要重新下载。
想拉指定版本的话加个标签:
docker pull nginx:1.27
docker pull nginx:alpine
不加标签默认拉 latest。
查看镜像
拉完了看看本地都有哪些镜像:
docker images
输出长这样:
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest abc123def456 2 weeks ago 192MB
各列的意思:
- REPOSITORY — 镜像名,比如 nginx、redis
- TAG — 标签/版本号,不指定就是 latest
- IMAGE ID — 镜像的唯一 ID
- CREATED — 镜像的创建时间(不是你的拉取时间)
- SIZE — 镜像大小
删除镜像
不需要的镜像删掉:
docker rmi nginx
或者用 IMAGE ID 删:
docker rmi abc123def456
如果有容器在用这个镜像,会提示删不掉。可以加 -f 强制删除,或者先把相关的容器删了再删镜像。
容器操作
运行容器
镜像拉好了,用 docker run 跑起来:
docker run nginx
这条命令会以前台模式启动 nginx。你会看到一堆日志刷出来,终端卡在那里——因为 nginx 在前台跑着,把控制台占了。
查看容器
再开一个终端,看看容器有没有跑起来:
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
abc123def456 nginx "/docker-entrypoint.…" 10 seconds ago Up 10 seconds 80/tcp clever_curie
能看到 nginx 已经在运行了,PORTS 那一列显示 80/tcp,但这里只是说容器内部开了 80 端口,并没有映射到宿主机。
docker ps 只显示当前正在运行的容器。想看所有容器(包括已停止的),加个 -a:
docker ps -a
试试访问 http://127.0.0.1:80——会发现访问不了。
这是因为 Docker 的网络是隔离的。容器内部有一个独立的网络空间,容器的 80 端口只对容器内部开放,从宿主机是访问不到的。要想让外部能访问,需要把容器的端口映射到宿主机上来。
运行容器:指定容器名
每次 docker run 如果不指定名字,Docker 会随机给一个名字,比如 clever_curie、hungry_elgamal,很难分清谁是谁。用 --name 指定名字:
docker run --name my-nginx -d -p 8080:80 nginx
指定了名字之后,后面 docker stop、docker start、docker rm 都可以直接用这个名字操作,不用记 ID。
如果名字跟已有的容器冲突了,会报错:
docker: Error response from daemon: Conflict. The container name "/my-nginx" is already in use
需要先 docker rm 删掉旧容器,或者换一个名字。
运行容器:端口映射
先按 Ctrl+C 停掉刚才的前台进程。然后用端口映射的方式重新启动。
自动映射:
docker run -P nginx
-P 会把容器内暴露的端口自动映射到宿主机的一个随机高位端口(比如 32768)。运行 docker ps 就能看到映射关系:
0.0.0.0:32768->80/tcp
这时访问 http://127.0.0.1:32768 就能看到 nginx 的欢迎页了。
指定映射:
docker run -p 8080:80 nginx
-p 8080:80 意思是将宿主机的 8080 端口映射到容器的 80 端口。访问 http://127.0.0.1:8080 即可。
运行容器:退出时自动删除
加 --rm 参数,容器一停就会自动删掉,省得 docker ps -a 里一堆残留:
docker run --rm -d -p 8080:80 nginx
注意这个删除是跟容器状态挂钩的——不管是自己退出,还是你用 docker stop 手动停掉,容器都会被删掉。
运行容器:限制资源
默认情况下容器能用到宿主机的全部资源,这显然不行——一个容器把内存吃光了,其他程序就遭殃了。用 -m 限制内存,--cpus 限制 CPU:
docker run -d --name my-nginx -m 512m --cpus 0.5 -p 8080:80 nginx
-m 512m— 内存最多用 512MB--cpus 0.5— 最多用半个 CPU 核心
容器超过内存限制会被 OOM kill,加上 --restart on-failure 可以在被 kill 后自动拉起来。
查看容器状态
想知道容器占了多少资源,用 docker stats:
docker stats
会实时显示所有运行中容器的 CPU、内存、网络 IO 和磁盘 IO:
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O
abc123def456 my-nginx 0.01% 5.32MiB / 512MiB 1.04% 1.2kB / 648B
按 Ctrl+C 退出。
docker ps 看的是容器生命周期状态(Up、Exited 等),docker stats 看的是运行时资源状态,两个配合用。
运行容器:环境变量
很多镜像需要通过环境变量来配置,用 -e 或 --env 传入:
docker run -d --name my-mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:8
多个环境变量就写多个 -e:
docker run -d --name my-app -e DB_HOST=localhost -e DB_PORT=3306 -e DB_USER=root my-app
环境变量在容器启动时注入,容器里的程序可以直接读取。
运行容器:重启策略
用 --restart 指定容器退出时的重启策略,常用的有三种:
no— 默认值,容器退出后不自动重启on-failure— 容器异常退出(退出码非 0)时自动重启。注意是异常退出才重启,如果你手动docker stop,退出码是 0,不会重启always— 只要容器一停就自动重启,包括机器重启后 Docker 服务启动也会把容器拉起来。不过手动docker stop同样不会重启,要等到下次 Docker 服务重启才会再起来
docker run -d --restart always --name my-nginx -p 8080:80 nginx
简单总结:想让容器挂了自动拉起来用 always,只在意程序崩溃(非正常退出)用 on-failure。
运行容器:后台运行
每次开个终端跑前台进程太麻烦,用 -d 让它后台运行:
docker run -d -p 8080:80 nginx
加了 -d 之后终端不会被占住,容器在后台安安静静地跑着,docker ps 照样能看见它。
停止容器
正在运行的容器用 docker stop 停掉:
docker stop clever_curie
停掉之后 docker ps 就看不到了,但 docker ps -a 还能看到,状态会变成 Exited。
启动容器
已经停止的容器用 docker start 重新启动:
docker start clever_curie
注意 docker start 是启动一个已有的容器,不是重新创建一个。启动后容器的配置(端口映射、挂载卷等)跟之前一样。
删除容器
用 docker rm 删除容器,后面跟容器 ID 或名字:
docker rm abc123def456
名字可以从 docker ps 里看,比如 clever_curie:
docker rm clever_curie
如果容器正在运行,会提示删不掉。需要先停掉再删,或者直接加 -f 强制删除:
docker rm -f clever_curie
不过不推荐这么干,-f 是直接发 SIGKILL 把容器杀了,可能会丢数据。保险的做法是先停容器再删。
docker ps -a 能看到的容器都可以删,删完就没了。
查看容器日志
容器在后台跑着,怎么知道它在干什么?用 docker logs:
docker logs my-nginx
会打印出容器所有的标准输出和标准错误日志,跟你在前台跑时看到的刷屏内容一样。
日志太多的话用 -n 只看最后几行:
docker logs -n 50 my-nginx
想实时跟踪日志输出,加 -f(跟 tail -f 一个意思):
docker logs -f my-nginx
加了 -f 终端会一直挂着,有新日志就自动打印出来,按 Ctrl+C 退出。
数据卷映射
默认情况下容器里产生的数据,容器一删就全没了。而且你想改容器里的配置文件,得先进去再改,很麻烦。
用 -v 把宿主机的一个目录映射到容器里:
docker run -d -p 8080:80 -v /path/to/html:/usr/share/nginx/html nginx
-v /宿主机路径:/容器路径,冒号左边是宿主机目录,右边是容器目录。
这样你在本地改文件,容器里马上就能看到,反过来容器写的数据也会落到本地磁盘上,删了容器数据还在。
举个例子,挂载 nginx 的配置文件和页面目录:
docker run -d -p 8080:80 \
-v /home/myuser/nginx/html:/usr/share/nginx/html \
-v /home/myuser/nginx/nginx.conf:/etc/nginx/nginx.conf \
nginx
这样以后改页面、改配置都在本地搞,不用进容器了。
想进到容器里看看,或者在里面执行命令,用 docker exec:
docker exec -it my-nginx bash
-i— 交互模式,保持标准输入打开-t— 分配一个伪终端,让你能正常输命令
两个通常一起用,写成 -it。进去之后你就到了容器的 shell 里,可以随便看:
# 进去之后
ls /etc/nginx
cat /etc/nginx/nginx.conf
exit # 退出容器
不想进 shell,只想在容器里跑一条命令也行:
docker exec my-nginx ls /etc/nginx
这样会直接输出结果,不会进交互界面。
