用Git子模块和Docker Compose实现高效开发工作流

云计算
搭建开发环境一直让程序员们头疼,本文使用Git子模块和Docker Compose实现高效率的开发工作流,让程序员能够轻松搭建出开发环境,把精力投入到需要开发的应用本身。

用Git子模块和Docker Compose实现高效开发工作流

搭建开发环境一直让程序员们头疼,本文使用Git子模块和Docker Compose实现高效率的开发工作流,让程序员能够轻松搭建出开发环境,把精力投入到需要开发的应用本身。

问题

自我们从Continuous Software雇佣了第一位远程开发的程序员以来,我们就意识到精简开发工作流的重要性。当新入职的程序员接手由很多应用组成的复杂项目时,我们想尽量避免以下这几个问题:

  • 缺少stack模块:Node.js、PHP、PostgreSQL等
  • 不清楚项目组件/应用的总体概况
  • 本地配置冲突:监听端口、数据库配置等

此外,就我个人经验而言,我们这样的程序员太容易找不着北了。曾经,我入职一个公司的第一整天都花在搭建开发环境上,试图去理解所有的东西怎么才能一起工作,而无法直接就去理解公司开发的应用到底是怎么工作的。

方案

在具体介绍如何解决上述问题之前,我想先直接展示一下我们项目采用的开发工作流。

每个项目都在Bitbucket上有自己的Team(和GitHub上的Organization对应)。每个应用在Team下创建一个repository(比如,api、dashboard、cpanel)。在这些子模块之上,创建了一个名为development的repository。子模块的同一层级里,有README.md和docker-compose.yml两个文件。

 

  1. kytwb@continuous:~/path/to//$ ls -la 
  2.  
  3. total 40 
  4.  
  5. drwxrwxr-x 11 kytwb amine 4096 Mar 14 16:30 . 
  6.  
  7. drwxr-xr-x 4 kytwb amine 4096 Nov 1 20:17 .. 
  8.  
  9. drwxr-xr-x 20 kytwb amine 4096 Mar 11 14:24 api 
  10.  
  11. drwxr-xr-x 11 kytwb amine 4096 Mar 3 13:21 cpanel 
  12.  
  13. drwxr-xr-x 10 kytwb amine 4096 Mar 12 11:37 dashboard 
  14.  
  15. -rw-r--r-- 1 kytwb amine 2302 Mar 2 15:28 docker-compose.yml 
  16.  
  17. drwxrwxr-x 9 kytwb amine 4096 Mar 14 16:30 .git 
  18.  
  19. -rw-r--r-- 1 kytwb amine 648 Dec 22 17:20 .gitmodules 
  20.  
  21. -rw-r--r-- 1 kytwb amine 1706 Dec 17 16:41 README.md 

当新程序员加入项目时,只需在Bitbucket上浏览developmentrepository,根据README.md的步骤就可以快速搭建环境。具体步骤如下所示:

  1. $ git -v 
  2.  
  3. $ docker -v 
  4.  
  5. $ docker-compose -v 
  6.  
  7. $ git clone git@bitbucket.com:/development.git && cd 
  8.  
  9. $ git submodule init && git submodule update 
  10.  
  11. $ git submodule foreach npm install 
  12.  
  13. $ docker-compose up -d 

至此,一切就都已经搭建好,并运行在本地机器上了。

实现原理

本章介绍我们是如何实现上述工作流的。

前提条件

  1. $ git -v 
  2.  
  3. $ docker -v 
  4.  
  5. $ docker-compose 

我们的开发堆栈完全基于Docker。因此,程序员需要先安装Docker。这时他们不需要特别熟悉Docker,只需要在开发时使用Docker即可,我们间接地将他们引入了容器的世界,之后会以此为桥梁向他们解释如何使用Docker实现持续集成、持续交付等等。README.md中并没有详细介绍如何安装Docker,因为安装很简单。

当docker-compose还叫Fig的时候我们就已经用它来编排开发堆栈里的容器。之后Docker收购了Fig,重命名为Docker Compose。有人提议将Docker Compose合并到Docker代码里,但是基于很多原因最终并没有这么做,所以Docker Compose仍然需要单独安装。

同样地,本文没有详细介绍Docker Compose的安装,因为很简单。

搭建仓库(repository)

如前所述,需要创建一个开发仓库,以及为每个应用创建对应的仓库。这里我们创建了api、dashboard和cpanel。当创建这些仓库的时候,重点关注developmentrepository的搭建。

  1. $ git clone git@bitbucket.com:/development.git && cd  

现在将应用程序的仓库添加为developmentrepository的子模块。只需要键入如下命令:

  1. $ git submodule add git@bitbucket.org:/api.git 
  2.  
  3. $ git submodule add git@bitbucket.org:/dashboard.git 
  4.  
  5. $ git submodule add git@bitbucket.org:/cpanel.git 

这样,你的developmentrepository根目录下会创建出.gitmodules文件。程序员也就可以在克隆developmentrepository的时候一次得到所有的应用程序并运行:

  1. $ git submodule init && git submodule update 

更多子模块的信息,请参考Git官方文档。

#p#

Docker化一切

现在我们已经搭建好了developmentrepository,可以通过cd的方式访问所有不同的应用程序。接下来我们要用之前提到的编排工具:Docker Compose来容器化所有的应用及其配置。

首先从api应用程序开始。打开docker-compose.yml,为API声明一个容器,并为这个容器选择基础镜像。本示例中的代码基于Node.js,因此选择官方Node.js镜像:

  1. api: 
  2.  
  3. image: dockerfile/nodejs 

这时,运行命令docker-compose up -d会创建出一个名为<project>_api_1的容器,这个容器什么也不做(启动后立即退出)。运行命令docker-compose ps可以得到由docker-compose.yml编排的所有容器的信息。

接下来配置api容器,使其多一些功能。为了实现这个目的,我们需要:

  • 将源代码挂载到容器里
  • 声明用什么命令运行应用
  • 暴露合适的端口以供访问应用

这样配置文件类似:

  1. api: 
  2.  
  3. image: dockerfile/nodejs 
  4.  
  5. volumes: 
  6.  
  7. - ./api/:/app/ 
  8.  
  9. working_dir: /app/ 
  10.  
  11. command: npm start 
  12.  
  13. ports: 
  14.  
  15. "8000:8000" 

现在再运行docker-compose up -d,就启动了api应用,可以在http://localhost:8000访问它。这个程序可能会崩溃,可以使用docker-compose logs api检查容器日志。

这里,我怀疑api的崩溃是因为它连不上数据库。因此需要添加database容器,并让api容器能够使用它。

  1. api: 
  2.  
  3. image: dockerfile/nodejs 
  4.  
  5. volumes: 
  6.  
  7. - ./api/:/app/ 
  8.  
  9. working_dir: /app/ 
  10.  
  11. command: npm start 
  12.  
  13. ports: 
  14.  
  15. "8000:8000" 
  16.  
  17. links: 
  18.  
  19. - database 
  20.  
  21. database: 
  22.  
  23. image: postgresql 
  24.  
  25. ports: 
  26.  
  27. "5432:5432" 

通过创建database容器,并将其链接到api容器,我们就可以在api容器里找到database。要想展示API的环境(比如,console.log(process.env)),必须使用如下变量,比如POSTGRES_1_PORT_5432_TCP_ADDR和POSTGRES_1_PORT_5432_TCP_PORT。这是我们在API的配置文件里使用的关联到数据库的变量。

通过link指令,这个数据库容器被认为是API容器的依赖条件。这意味着Docker Compose在启动API容器之前一定会先启动数据库容器。

现在我们用同样的方式描述其它应用程序。这里,我们可以通过环境变量API_1_PORT_8000_TCP_ADDR和API_1_PORT_8000_TCP_PORT,将api连接到dashboard和cpanel应用。

  1. - ./api/:/app/ 
  2.  
  3. working_dir: /app/ 
  4.  
  5. command: npm start 
  6.  
  7. ports: 
  8.  
  9. "8000:8000" 
  10.  
  11. links: 
  12.  
  13. - database 
  14.  
  15. database: 
  16.  
  17. image: postgresql 
  18.  
  19. dashboard: 
  20.  
  21. image: dockerfile/nodejs 
  22.  
  23. volumes: 
  24.  
  25. - ./dashboard/:/app/ 
  26.  
  27. working_dir: /app/ 
  28.  
  29. command: npm start 
  30.  
  31. ports: 
  32.  
  33. "8001:8001" 
  34.  
  35. links: 
  36.  
  37. - api 
  38.  
  39. cpanel: 
  40.  
  41. image: dockerfile/nodejs 
  42.  
  43. volumes: 
  44.  
  45. - ./api/:/app/ 
  46.  
  47. working_dir: /app/ 
  48.  
  49. command: npm start 
  50.  
  51. ports: 
  52.  
  53. "8002:8002" 
  54.  
  55. links: 
  56.  
  57. - api 

就像之前为数据库修改API配置文件一样,可以为dashboard和cpanel应用使用类似的环境变量,从而避免硬编码。

现在可以再次运行docker-compose up -d命令和docker-compose ps命令:

  1. kytwb@continuous:~/path/to/$ docker-compose up -d 
  2.  
  3. Recreating _database_1... 
  4.  
  5. Recreating _api_1... 
  6.  
  7. Creating _dashboard_1... 
  8.  
  9. Creating _cpanel_1... 
  10.  
  11. kytwb@continuous:~/path/to/$ docker-compose ps 
  12.  
  13. Name Command State Ports 
  14.  
  15. ---------------------------------------------------------------------------------- 
  16.  
  17. _api_1 npm start Up 0.0.0.0:8000->8000/tcp 
  18.  
  19. _dashboard_1 npm start Up 0.0.0.0:8001->8001/tcp 
  20.  
  21. _cpanel_1 npm start Up 0.0.0.0:8002->8002/tcp 
  22.  
  23. _database_1 /usr/local/bin/run Up 0.0.0.0:5432->5432/tcp 

应用应该就已经启动并运行了。

从http://localhsot:8000可以访问api。

从http://localhsot:8001可以访问dashboard。

从http://localhsot:8002可以访问cpanel。

#p#

更进一步

本地路由

在使用docker-compose up -d运行所有容器之后,可以通过http://localhost:<application_port>访问我们的应用。基于当前配置,我们可以很容易地使用jwilder/nginx-proxy加上本地路由功能,这样就可以使用和生产环境类似的URL访问本地应用了。比如,通过http://api.domain.local访问http://api.domain.com的本地版本。

jwilder/nginx-proxy镜像将一切变得很简单。只需要在docker-compose.yml里加上描述去创建一个名为nginx的新容器。根据jwilder/nginx-proxy的README文件(挂载Docker守护进程socket,暴露80端口)配置该容器就可以了。之后,在现有容器里再添加额外的环境变量VIRTUAL_HOST和VIRTUAL_PORT,如下:

  1. api: 
  2.  
  3. image: dockerfile/nodejs 
  4.  
  5. volumes: 
  6.  
  7. - ./api/:/app/ 
  8.  
  9. working_dir: /app/ 
  10.  
  11. command: npm start 
  12.  
  13. environment: 
  14.  
  15. - VIRTUAL_HOST=api.domain.local 
  16.  
  17. - VIRTUAL_PORT=8000 
  18.  
  19. ports: 
  20.  
  21. "8000:8000" 
  22.  
  23. links: 
  24.  
  25. - database 
  26.  
  27. database: 
  28.  
  29. image: postgresql 
  30.  
  31. dashboard: 
  32.  
  33. image: dockerfile/nodejs 
  34.  
  35. volumes: 
  36.  
  37. - ./dashboard/:/app/ 
  38.  
  39. working_dir: /app/ 
  40.  
  41. command: npm start 
  42.  
  43. environment: 
  44.  
  45. - VIRTUAL_HOST=dashboard.domain.local 
  46.  
  47. - VIRTUAL_PORT=8001 
  48.  
  49. ports: 
  50.  
  51. "8001:8001" 
  52.  
  53. links: 
  54.  
  55. - api 
  56.  
  57. cpanel: 
  58.  
  59. image: dockerfile/nodejs 
  60.  
  61. volumes: 
  62.  
  63. - ./api/:/app/ 
  64.  
  65. working_dir: /app/ 
  66.  
  67. command: npm start 
  68.  
  69. environment: 
  70.  
  71. - VIRTUAL_HOST=cpanel.domain.local 
  72.  
  73. - VIRTUAL_PORT=8002 
  74.  
  75. ports: 
  76.  
  77. "8002:8002" 
  78.  
  79. links: 
  80.  
  81. - api 
  82.  
  83. nginx: 
  84.  
  85. image: jwilder/nginx-proxy 
  86.  
  87. volumes: 
  88.  
  89. - /var/run/docker.sock:/tmp/docker.sock 
  90.  
  91. ports: 
  92.  
  93. "80:80" 

nginx容器会检查所有运行在Docker守护进程之上(通过挂载的docker.sock文件)的容器,为每个容器创建合适的nginx配置文件,并设置VIRTUAL_HOST环境变量。

要想完成本地路由的搭建,还需要在etc/hosts里添加所有的VIRTUAL_HOST。我是手动用node.js的hostile包来完成这个工作的,不过我猜应该可以自动化实现,就像jwilder/nginx-proxy可以根据nginx配置文件动态变化一样。这里需要再研究一下。

现在可以再次运行docker-compose up -d,然后使用和生产环境一样的url访问应用程序,只需用.localTLD代替.comTLD。

建议

本文发表在AirPair上,如果你对更进一步这一章有任何建议,请随意fork并修改它。如果你发现本文有任何错误,也请帮忙修改。

原文链接:http://dockerone.com/article/265
 

责任编辑:Ophira 来源: dockerone
相关推荐

2015-12-30 13:58:00

DockerGit开发环境

2015-06-24 10:18:26

2009-09-22 12:15:06

ibmdwLotus

2022-02-21 10:50:28

SvnGitHub分支

2011-05-25 17:04:41

ibmdwLotus

2009-03-03 09:13:36

工作流BPM业务流程

2021-02-20 06:11:07

Git-Flow工作流分支

2022-07-10 21:17:01

GitTigLinux

2021-01-05 20:24:04

Git开源软件开发

2022-10-26 08:00:43

Activiti工作流BPM

2021-10-14 11:34:05

技术工作流引擎

2022-02-22 08:29:53

huskylint 工具

2023-01-05 13:36:41

Script优化任务

2020-02-27 15:53:01

开发技能代码

2015-03-13 15:58:11

Adobe

2013-04-23 10:28:08

IBeamMDAAWF

2024-04-25 08:00:00

DevOps架构软件开发

2022-07-07 08:38:15

Springflowable引擎

2024-04-07 00:06:00

Rust编程技巧

2016-03-03 15:11:42

Spark Strea工作流调度器
点赞
收藏

51CTO技术栈公众号