现在部署服务几乎都是使用 docker 了。VPS 不用说自己都能装上 docker,Nas 新版的系统也都支持上了。这里分享下自己管理 docker 服务的方法。目前 Nas 上和几台 VPS 上都是使用的同样的方式。

目录结构

我不是用的 docker run 而是用 docker compose,好处是一个配置文件对应一个服务,可以用 git 管理配置变更,修改和重启都方便。
对于一台机器,所有的服务我都放在 /opt/app/ 下面(这个目录也可以是其他目录的软链接),放这里是离根目录层级不深,在写 crontab 时方便。
然后子目录下一个目录一个服务,比如

|-- app  
|  |-- emby  
|  |-- nginx
|  |-- moviepilot  
|  |-- gitea

对于一个目录里,又主要有三类文件,一是 docker-compose.yaml+.env,这是 docker 服务的主要文件,二是 _data 目录(有也还会建一个 _config,都是放容器里的数据),主要是用于容器存处自己的数据,三是另外自定义的配置文件。
拿 gitea 来说。

|-- gitea
|  |-- .env
|  |-- docker-compose.yaml
|  |-- _data

docker-compose.yaml+.env

长这样

# docker-compose.yaml
services:
  server:
    image: gitea/gitea:1.22.5
    container_name: gitea
    environment:
      - USER_UID=1000
      - USER_GID=1000
      - GITEA__database__DB_TYPE
      - GITEA__database__HOST
      - GITEA__database__NAME
      - GITEA__database__USER
      - GITEA__database__PASSWD
      - DISABLE_REGISTRATION=true
      - REQUIRE_SIGNIN_VIEW=true
    restart: always
    networks:
      - gitea
    volumes:
      - ./_data:/data
      - /etc/localtime:/etc/localtime:ro
    ports:
      - "13100:3000"
      - "13101:22"
    extra_hosts:
      - "host.docker.internal:host-gateway"
networks:
  gitea:
    external: false

里面有两个要关注的,一是 environment 里的这些数据库的变量没有直接写到 docker-compose.yaml 里

- GITEA__database__DB_TYPE
- GITEA__database__HOST
- GITEA__database__NAME
- GITEA__database__USER
- GITEA__database__PASSWD

而是写到了 .env 里。我这样做主要是为了复用 docker-compose.yaml,如果想简单也可以直接在 docker-compose.yaml 里写。

# .env
GITEA__database__DB_TYPE=mysql
GITEA__database__HOST=host.docker.internal:11201
GITEA__database__NAME=gitea
GITEA__database__USER=xxx
GITEA__database__PASSWD=xxx

_data

_data 目录直接挂载到了容器里 - ./_data:/data 作为 gitea 的工作目录,gitea 自己产生的数据都放在这里面。我不怎么关心

其它

假如还有我需要关注的自定义配置的 custom 目录,那就另外建一个,然后挂载进容器。

Compose 配置简单介绍

这里简单介绍下 docker compose 配置文件,更具体内容可以去问 gpt。还是拿上面的文件举例

# 以前需要这个,现在不需要了,是自动识别了,可以删掉。
version: "3" 
# 描述有 services(服务,容器服务),对等的还有 volums(卷,存储地址),networks(网络,网络配置)等
services: 
# 这个服务的名称
  server: 
	# 容器镜像,本质上是一堆文件通过特殊方式打的包
    image: gitea/gitea:1.22.5 
    # 容器名称
    container_name: gitea 

# 上面这些配置都不算重要,根据别人的教成抄就行。

	# 环境变量(给容器用的配置),有一些服务需要自己去修改,比如这里配置数据库信息,
	# 可以直接在这里赋值,像 USER_GID 一样,
	# 也可以写成变量,让 docker 去 .env 里找对应的值,像 GITEA__database__DB_TYPE 就是指 docker 要去 .env 里找 GITEA_DB_TYPE 对应的值填到这里来。
	# GITEA__database__HOST 和 GITEA__database__HOST=${GITEA__database__HOST} 一样。
    environment:
      - USER_UID=1000
      - USER_GID=1000
      - GITEA__database__DB_TYPE=${GITEA_DB_TYPE}
      - GITEA__database__HOST
      - GITEA__database__NAME
      - GITEA__database__USER
      - GITEA__database__PASSWD
      - DISABLE_REGISTRATION=true
      - REQUIRE_SIGNIN_VIEW=true
	# 一直运行的服务就写 alway 就行,一般 selfhost 的都是 always 或者 unless-stopped
    restart: always
    # 指定 bridge 的网络名,一般参考网上的话,这里也不用管。
    networks:
      - gitea
    # 这个很重要,描述我们把宿主机的哪个目录映射到容器里的哪个目录,一般都要配置,而且宿主机(运行 docker 的机器)的目录需要手动创建。
    volumes:
      - ./_data:/data
      - /etc/localtime:/etc/localtime:ro
    # 这里也很重要,容器里默认的网络是独立的(bridge 模式),就像 volume 一样,我们也需要映射,这里就是宿主机的 13100 端口映射到容器的 3000 端口,所以在宿主机访问时要访问 13100。
    # 如果把网络模式改成 host,即使用宿主机的网络(在这个 ports 同级加上 network_mode: host),就不需要映射端口了,容器会直接用宿主机的端口,那样在宿主机访问就直接用 3000 了
    ports:
      - "13100:3000"
      - "13101:22"
    # 这里主要用于 bridge 模式下从容器里访问宿主机的端口,正常在宿主机里访问自己的比如 8080 端口就是 127.0.0.1:8080,但是在容器里这样访问访问的是容器里的 8080 端口,所以要添加下面这样的 host,然后用 host.docker.internal:8080 访问。(host 模式下 127.0.0.1:8080 是没问题的)。
    extra_hosts:
      - "host.docker.internal:host-gateway"
# 网络名,可以不关注
networks:
  gitea:
    external: false

常用命令

当用上面的方式配置好后就可以启动服务了。
可以先用 docker compose up 启动,查看日志有没有报错,有报错就修改,完全启动后可以再改成 docker compose up -d 后台启动。
如果修改了配置想重新启动用 docker compose up -d --force-recreate
想停止运行的容器用 docker compose stop
查看日志 docker compose logs,加上 -f 就是一直刷新最新的日志。
docker exec -it <container_name> sh 可以进入容器。

备份

使用上面的方式管理 docker 后,一个服务的所有数据都在 /opt/app/ 目录下。想备份和迁移只需要打包这整个目录,然后在另外一台机器上解压执行 docker compose up -d 即可启动(当然要是依赖了外部服务,比如数据库还需要先配置好外部服务)。
备份我使用的是 gobackup,每天整体将 /opt/app 目录打包存到了一个对象存储里。
配置可以参考这里