目前我们公司已经深度的使用 Docker 来部署项目,在推进 Docker 落地的过程中,如何将 Docker 的配置文件更好的融入项目一直是困扰着我们的问题。

刚开始我们把 Docker 配置文件全部一股脑地放在项目里, 使编程架构和部署架构给混在了一起,如果开发和部署是一拨人倒还好,如果开发和部署是分开的两个工种,这种方式会造成一定程度的混乱。

以我们 Laravel 项目目录结构为例
.
├── app
├── artisan
├── bootstrap
├── composer.json
├── composer.lock
├── config
├── database
├── docker
├── docker-compose.yml
├── Dockerfile
├── .editorconfig
├── .env.example
├── .git
├── .gitattributes
├── .gitignore
├── .gitlab-ci.yml
├── package.json
├── .php-cs-fixer.cache
├── phpunit.xml
├── public
├── README.md
├── resources
├── rolling-update.sh
├── routes
├── storage
├── tests
├── vendor
└── vite.config.js

加粗的 docker、Dockerfile、docker-compose.yml 属于部署架构,其他的属于开发架构,这种开发架构和部署架构混在一起,无疑是造成一定程度的混乱,尤其在交接或协作过程中,后来在一篇国外的技术博客里找到了答案。

作者也遇到了和我们类似的问题,作者提供了一种新的项目组织形式结构如下

├── application
├── docker
├── Makefile
└── var

虽然作者介绍时使用的是 Go 语言的项目,但我觉得这种目录结构并不局限于开发语言,任何项目都可以用这种方式来组织。

目录介绍

application

application 比较容易理解就是应用目录,我们把 Laravel 框架的所有文件放在了 application 下面,开发人员只需要关注这个目录即可。

docker

docker
├── local # 本地开发环境
├── prod # 线上环境
└── test # 测试环境

docker 目录用于存放各种环境下的 Docker 配置文件,你可以根据自己的需要随意增减。环境文件夹结构大概如下:

├── docker-compose.yml
├── Dockerfile
└── supervisor
    └── config
        ├── conf.d
        │   └── cron.conf
        └── supervisord.conf

主要用于存放镜像的构建、容器的组织和容器服务的配置文件

Makefile

Makefile 文件是用来定义项目构建的脚本,内容如下:

# Development environment commands
local-build:
        docker compose -f ./docker/local/docker-compose.yml build

local-up:
        docker compose -f ./docker/local/docker-compose.yml up -d

local-down:
        docker compose -f ./docker/local/docker-compose.yml down

# Production environment commands
test-build:
        docker compose -f ./docker/test/docker-compose.yml build

test-up:
        docker compose -f ./docker/test/docker-compose.yml up -d
        ./rolling-update.sh master
test-down:
        docker compose -f ./docker/test/docker-compose.yml down

test-logs:
        docker compose -f ./docker/test/docker-compose.yml logs -f

Var

Var 目录是用来存储容器服务的日志的,比如 supervisor 维护的服务等,目录结构如下:

var
└── log
    └── supervisor
        ├── cron.err
        ├── cron.log
        └── supervisord.log

这样做整体项目会比较清晰,运维和开发各司其职,都可以轻松的找到自己需要的文件,且互不打扰。

一些问题

关于 docker 目录里会遇到配置文件复用问题,对于这样的问题我的看法是这类配置文件本身改动频率不高,清晰的优先级大于复用,因此我们每个环境都是单独配置。

这样做的好处是环境的构建相对独立,不会因为一个环境的构建脚本发生变化而影响其他环境。不同环境在增减服务也比较自由。

关于文中的架构,我们已经在项目中初步尝试,目前用下来感觉良好,这种明确的目录结构,以及 Makefile 的引入,让整个项目的维护成本降低不少,无需写繁琐的部署文档,仅需一行命令就可以启动整个项目,这也是我们积极投身虚拟化的美好收益之一吧。

References

Laravel12 模板地址
Docker for Go: Setup for Development, Testing, and Production