Docker 像是一个容器一样,能够让应用运行在隔离的环境中。其实很像一个虚拟机,但是其本质和虚拟机是不同的,结构较虚拟机简单的多,因此速度也远快于虚拟机。
Docker 还是跨平台的,可以在 Linux/Windows/MacOS 上运行。
对于 Windows 的 Docker(准确的说是 Docker Desktop),它还提供了 Linux 和 Windows 两种子系统。(也就是说,在 Linux 下能运行的 Docker 容器,完全能够在 Windows 上运行)

而 Docker Compose 可以根据配置文件自动下载镜像、配置、运行 Docker 容器,一气呵成。
下载网上写好的配置文件,然后一行代码 docker-compose 即可完成配置,搭建好自己的云服务。它同样是跨平台的。这也是 Docker 方便的原因之一。

我收集的基于 Docker 的好用的云服务可以见后面小节

# 安装、使用

# Linux 发行版安装

Debian/Ubuntu/Fedora/CentOS/RHEL 可使用清华源 (opens new window)安装。

Manjaro 直接走 sudo pacman -S docker 即可。

安装完成以后 docker ps 没有权限,可以把当前用户加到 docker 用户组:

sudo groupadd docker
sudo usermod -aG docker $USER
newgrp docker   # log in to docker group
docker ps       # 验证更改成功

# 加入阿里源

sudo wget -o /etc/docker/daemon.json https://blog.lyh543.cn/mirrors/docker.json
sudo systemctl restart docker.service

# 在 Docker Pull 时使用梯子

Cannot download Docker images behind a proxy - Stack Overflow (opens new window)

创建文件夹和配置文件:

sudo mkdir /etc/systemd/system/docker.service.d
sudo vim /etc/systemd/system/docker.service.d/http-proxy.conf

写入以下配置:

[Service]
Environment="HTTP_PROXY=http://localhost:17296/"
Environment="HTTPS_PROXY=http://localhost:17296/"

刷新并重启 docker

sudo systemctl daemon-reload
sudo systemctl restart docker

# 安装 docker-compose

sudo apt install docker-compose # debian
sudo pacman -S docker-compse    # manjaro

# 在 WSL 1 中使用 docker-cli

WSL 2 中集成了 docker-cli,可以直接管理 Windows 的 Docker。在 WSL 1 中输入 docker,可以看到 Docker 推荐你转换为 WSL 2。

The command 'docker' could not be found in this WSL 1 distro.
We recommend to convert this distro to WSL 2 and activate
the WSL integration in Docker Desktop settings.
 
See https://docs.docker.com/docker-for-windows/wsl/ for details.

然而我并不想转换,可参考 Windows 10 WSL1 的子系统下完美解决docker的命令问题_累积技术 沉淀经验-CSDN博客 (opens new window) 在 WSL1 下安装 docker-cli

# 常用 Docker 镜像

个人收集的一些基于 Docker 的云服务。

# 云盘

镜像 创建命令或 docker-compose.yml 链接
私人云 NextCloud nextcloud-docker-compose.tar
私人云 Seafile (opens new window) docker-compse.yaml (opens new window)
WebDAV docker run -d --name webdav -v /srv/dav:/var/lib/dav -e AUTH_TYPE=Digest -e USERNAME=test -e PASSWORD=test -p 80:80 --restart always bytemark/webdav

# 在线文档

镜像 创建命令或 docker-compose.yml 链接
在线 Markdown 编辑器 CodiMD (opens new window) docker-compse.yml (opens new window)
在线 LaTeX 编辑器 Overleaf (opens new window) docker-compose.yml (opens new window)

# 数据库

镜像 创建命令或 docker-compose.yml 链接
PostgreSQL docker run --name postgres -p 5432:5432 -e POSTGRES_PASSWORD=test -d --restart always postgres
MySQL docker run -d --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=test --restart always mysql
Redis docker run -d --name redis -p 6379:6379 -e REDIS_PASSWORD=test --restart always redis /bin/sh -c 'redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}'
Memcached docker run -d --name memcached -p 11211:11211 --restart always memcached
Hive docker-compose.yml (opens new window)

# 魔法

镜像 创建命令或 docker-compose.yml 链接
shadowsocks (opens new window) docker run --name shadowsocks -d -p 54285:54285 --restart always oddrationale/docker-shadowsocks -s 0.0.0.0 -p 54285 -k yourpasswd -m aes-256-cfb
V2RayA 服务器端 (opens new window) docker run -d --name v2ray -p 443:443 -p 80:80 -v $HOME/.caddy:/root/.caddy pengchujin/v2ray_ws:0.10 YOURDOMAIN.COM V2RAY_WS && sleep 3s && sudo docker logs v2ray
V2RayA 客户端 (Linux) (opens new window) docker run -d --restart=always --privileged --network=host --name v2raya -v /etc/v2raya:/etc/v2raya mzz2017/v2raya
V2RayA 客户端 (MacOS) (opens new window) docker run -d -p 2017:2017 -p 20170-20172:20170-20172 --restart=always --name v2raya -v /etc/v2raya:/etc/v2raya mzz2017/v2raya

# 其他

镜像 创建命令或 docker-compose.yml 链接
Docker Web 管理 docker run -d -p 8000:8000 -p 9000:9000 --name=portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce
Qbittorrent Enhanced Edition docker run -d --name qbittorrentee -e WEBUIPORT=8081 -e PUID=1026 -e PGID=100 -e TZ=Asia/Shanghai -p 6881:6881 -p 6881:6881/udp -p 8081:8081 -v /media/Downloads:/downloads --restart always superng6/qbittorrentee
云 SSH WebSSH2 (opens new window) docker run -d --name webssh -p 2222:2222 oldiy/docker-webssh2
云 Firefox firefox-enpass-novnc (opens new window) docker run -d --name firefox -p 8083:8083 -p 5900:5900 oldiy/firefox-enpass-novnc:latest

# Docker 基础命令

初次接触 Docker,要记得两个概念:images(镜像) 和 containers(容器)。从网上获取一个镜像,然后每次可以由这个镜像创造一个容器(像是每次由一个系统镜像安装一个系统一样)。

下面是我最先接触到的几条命令,可能比较适合和我一样的新人。

命令 用途 常用参数
docker run -dit ubuntu 从 Ubuntu 镜像创造一个容器并运行 可用 --name 对容器命名,默认名是随机生成的;在最后可加 <command>
docker start -i <name> 运行名为 <name>(也可以是容器的 container ID 值的前几位)的容器
docker images 查看本地的镜像
docker image prune -af 删除所有没有使用的镜像(如果有容器使用了某镜像,无论这个容器正在运行/已停止,这个镜像不会被删除)
docker ps 查看正在运行的容器 --all-a 查看所有的(包括已停止的镜像)
docker container rm <name> 删除名为 <name>(也可以是容器的 container ID 值的前几位)的容器
docker container prune -af 删除所有已停止的容器
docker container rename <old_name> <new_name> 给容器改名
docker exec -it <name> /bin/bash 在正在运行的 <name> 容器中运行 bash 命令行
docker update --restart=always <name> <name> 容器开机自启、自动重启
-v ~/downloads:/var/webdav 将容器外的 ~/downloads 映射到容器内的 /var/webdav Windows 下将路径中 \ 改为 / 即可,如 d:/Downloads

# Docker Compose 基础命令

命令 用途 常用参数
docker-compose up 以当前文件夹下的 docker-compose.yml 作为配置文件,run 一个容器 -d可在后台运行
docker-compose down -v 删除当前文件夹下的 docker-compose.yml 所指的容器

# Docker 空间清理

参考:https://blog.fundebug.com/2018/01/10/how-to-clean-docker-disk/

使用 docker system df 查看 Docker 占了多少空间:

$ docker system df
TYPE                TOTAL               ACTIVE              SIZE                RECLAIMABLE
Images              147                 36                  7.204GB             3.887GB (53%)
Containers          37                  10                  104.8MB             102.6MB (97%)
Local Volumes       3                   3                   1.421GB             0B (0%)
Build Cache                                                 0B                  0B
  • docker system prune 命令可以用于清理磁盘,删除关闭的容器、无用的数据卷和网络,以及 dangling 镜像(即无 tag 的镜像)。
  • docker system prune -a 命令清理得更加彻底,可以将没有容器使用 Docker 镜像(包括暂时未用到的容器和镜像)都删掉。

如果你使用的是基于 Windows WSL 2 的 Docker,上面的操作只会释放 WSL 2 中的空间,WSL 2 占用 Windows 的空间并不会自动缩小。需要在管理员 PowerShell 下手动缩小 %LOCALAPPDATA%\Docker\wsl\data\ext4.vhdx

# 关闭 Docker
net stop com.docker.service
kill -Force -Name "docker", "Docker Desktop"
wsl --shutdown
# 缩小磁盘
Optimize-VHD -Mode Full -Path $Env:LOCALAPPDATA\Docker\wsl\data\ext4.vhdx

# 常见错误及解决办法

# 在 Docker 容器中如何安装软件

不少 Docker 容器都是采用的 Alpine Linux,这个 linux 发行版没有 sudo,没有 bash,我猜是为了简洁吧,毕竟要做成镜像,所以把没用的功能尽量都砍了。

Alpine Linux 下安装软件的命令为:

apk add <package name>

顺便中科大镜像源也有 Alpine Linux 的软件源,觉得国内网速慢的可以去更换,镜像站也有更换教程。

# Read-only file system

可能是 docker-compose.yml 中指定了目录为只读。这些可能出现在:

version: '3.3'
 
services:
  redis:
    image: redis:4.0.1-alpine
    networks:
      - myoverlay
    read_only: true # 指定为只读
    
networks:
  myoverlay:
  web:
    build: ./web
    restart: always
    ports:
      - 7070:80
    volumes:
      # - nextcloud:/var/www/html:ro   # ro 为只读 (read-only)
      - nextcloud:/var/www/html        # 可读写的版本
    depends_on:
      - app

# Container is unhealty

我在 Windows 下安装 overleaf 时,出现过下面的情况。

> docker-compose up
Creating network "overleaf_default" with the default driver
Creating overleaf_redis ... done
Creating overleaf_mongo ... done

ERROR: for sharelatex  Container "233abaae4ea7" is unhealthy.
ERROR: Encountered errors while bringing up the project.

在配置文件 docker-compose.yml 中写到,sharelatex 基于 overleaf_redisoverleaf_mongo,并且要求 mongo 是 healthy 的。
233abaae4ea7 正是我电脑上的 mongo 的 Container ID。

sharelatex:
    depends_on:
        mongo:
            condition: service_healthy
        redis:
            condition: service_started
mongo:
    healthcheck:
        test: echo 'db.stats().ok' | mongo localhost:27017/test --quiet
        interval: 10s
        timeout: 10s
        retries: 5

healthy 可以理解为是正常运行。

这里出错就有两种情况了,一是 mongo 本身不正常了,另一种是 mongo 检查的太频繁了,导致还没完成启动,就被诊断为 unhealthy 了。

我们检查一下 mongo 的 log。

> docker ps | find "233a"
233abaae4ea7        mongo                                   "docker-entrypoint.s鈥?   About a minute ago   Restarting (14) 47 seconds ago                            overleaf_mongo

显示 mongo 正在重启,我估计是在反复不正常-重启,因此就考虑在这方面进行 debug。
最后的问题出在由于我是在 Windows 上运行,文件映射可能不正确,我把配置文件的 volumes 部分删掉就可以了。

当然,如果是正确的情况,上一行会显示:

> docker ps --all | find "mongo"
194bafd8158f        mongo                                   "docker-entrypoint.s鈥?   13 minutes ago      Up 12 minutes (healthy)   27017/tcp                overleaf_mongo

这种情况下,可以考虑把 mongohealthcheck 部分的 intevaltimeout 调大。