使用docker设置开发环境

我在为我的团队设置一个开发环境的docker时遇到了一些问题。 至今:

1)我用一个基本的图像来启动一个容器

docker run -t -i ubuntu:latest "/bin/bash" 

2)我安装了所有的编译和构build工具3)我承诺这个图像,并将其推送到我们的本地docker服务器

 docker commit e239ab... 192.168.10.100:5000/team-dev:beta 

到现在为止还挺好。 现在,作为一名团队成员:

1)我拉我的电脑上的开发环境图像

 docker pull 192.168.10.100:5000/team-dev:beta 

2)我启动一个容器:

 docker run -t -i 5cca4... "/bin/bash" 

在这一点上,我正在考虑将我的容器作为一种远程机器,我可以通过SSH进入和运行。

我尝试从容器内部做一个git clone ,但是由于公钥问题而失败了。 我手动将id_rsa *文件复制到docker中,并且克隆工作。 然后我尝试编辑一些源文件,但是我的vimconfiguration,bashconfiguration,一切都被抛弃了,因为这是一个全新的操作系统环境。 什么工作得很好是我的整个依赖版本化的生成环境。


这些是我想要帮助我解决这个问题的可能解决scheme。

1)拉出基本图像后,使用dockerfile将所有环境variables从主机添加到泊坞窗。

缺点:每次我的主机环境改变bash / vim / git我需要更新dockerfile

2)使用从主机到容器的卷。 Git克隆和编辑主机中的文件。 在Docker中运行构build脚本和编译。

缺点:如果需要,数据卷中的内容不能用于更新图像。 我不知道这是否是我应该关心的东西。

还是我以错误的方式接近?

作为一个年轻的docker使用者,我会试着解释一下我的用法。 我主要使用它来做两件事:隔离服务和容器复杂的环境。

1.隔离服务

抽象

分离关注原则

为什么? 对于可重用性可伸缩性 (顺便debugging和维护)。
例如,要有一个PHP Laravel网站的开发环境,我会运行一些容器:

  • Mysql的
  • Apache的PHP
  • Redis的
  • ..

这些容器(服务)中的每一个都将彼此链接 ,以便他们可以一起工作。 例如:

 Apache <== Mysql (3306 port). 

Apache容器现在可以通过公开的 3306端口打开到Mysql容器的TCP连接。

类似的项目将依赖于一个单一的Docker镜像,但将运行在不同的容器中。 但是为了团队合作,应用程序所需的每个工具都应该集装箱化。

源代码pipe理

我从来没有把源代码直接放在容器中。 我更喜欢通过容器docker run -v选项 )将其挂载到容器中。

当我想运行一个可以改变我的源代码的命令 ,比如build,运行tests或npm更新,我可以从主机或者容器中执行,具体取决于这个工具需要运行多lessconfiguration。
越是复杂或应用程序特定的,我会考虑在容器中做的越多。

运行容器

按照上面的例子,我将运行一个myapp和一个mysql容器。

 $ cd myapp $ docker run -d \ # run as deamon (detached) -p 82:80 \ # bind container's port 80 to host's 82 -p 22001:22 \ # bind container's port 22 to host's 22001 --expose 3306 # exposed to other container linked with it --name mysql author/mysqlimage $ docker run -d \ # run as deamon (detached) -p 81:80 \ # bind container's port 80 to host's 81 -p 22001:22 \ # bind container's port 22 to host's 22001 -v $(pwd):/var/www # mount current host's directory to container's /var/www --link mysql:db # give access to mysql container (ports) as db alias --name myapp author/apacheimage 

myapp容器将能够与mysql容器交谈。 testing它: $ telnet db 3306将工作。

运行容器使用Fig

就像我说的,Docker的cmd对我来说是噩梦,所以我find了另一个很棒的工具, Fig这让我最终得到了这个清晰的yaml文件,它位于我的项目的根目录:

 web: image: lighta971/laravel-apache links: - db ports: - "81:80" - "22001:22" volumes: - .:/app db: image: lighta971/phpmyadmin-apache ports: - "82:80" - "22002:22" expose: - "3306" 

然后$ cd myapp && fig up给出与下面的命令相同的结果:)

2.容纳复杂的环境

我也使用Docker进行Android开发。 一个基本的安卓/cordova设置是巨大的,像下载的演出,这需要时间来设置environement。
这就是为什么我把所有的组件放到一个“瑞士军刀”容器里:

  • Android SDK
  • Android NDK
  • Apache Ant
  • Android工具
  • Java的

它会产生一个图像,包含我需要设置Cordova环境的所有内容:

 $ docker run -i --privileged # special permission for usb -v /dev/bus/usb:/dev/bus/usb # mount usb volume -v $(pwd):/app # mount current folder -p 8001:8000 lighta971/cordova-env 

我在cvd别名:

 $ alias cdv='docker run -i --privileged -v /dev/bus/usb:/dev/bus/usb -v $(pwd):/app -p 8001:8000 lighta971/cordova-env' 

现在我可以透明地使用容器内的所有程序,就好像它已经安装在我的系统上一样。 例如:

$ cdv adb devices#列出usb设备$ cdv cordova build android#build立应用程序$ cdv cordova run android#在设备上运行应用程序$ cdv npm update#更新应用程序dependencies

由于卷装入选项$(pwd):/app所有这些命令将工作到当前目录。

Dockerfile

所有这一切说,还有其他的事情要知道,如:

  • 了解构build过程,以制作高效的图像
  • 处理持续数据的需求
  • 保持图像包更新
  • 等等

希望对你很清楚:)

我已经尝试了很多不同的开发环境设置在docker工作。

我的团队所坚持的是一个预定义的目录,代码将被放置在Docker容器中作为一个目录。 必要的环境variables放在Dockerfile中,并且写了一堆bash脚本来启动映射到的必要path的容器。我们将Dockerfile存储在Git中,每次添加新的依赖项时,都必须更新Dockerfile和可能重build的图像(这主要是由于我们如何处理依赖pipe理,这是不理想的,我不认为这是必要的,但将取决于技术堆栈)

我们的脚本是每种技术,由于我们使用了多less种不同的技术。 我们所有的容器都会映射到存储所有configuration的特定技术文件夹。 例如,/ opt /目录成为我们代码所在的主目录。 当docker run命令运行时,它会将本地/ opt /目录映射到docker容器中的/ opt /目录。

这一般工作。

尽pipe如此,build立当地的发展环境也是自己的挑战。 我开始使用Windows机器,这将从git拉。 我已经映射到运行docker的Ubuntu VM。

在Ubuntu VM中,我有bash脚本来启动所有需要的docker容器。

 ./start-apache.sh ./start-mysql.sh ./start-mongodb.sh ... and so on 

当我发现由于使用Windows作为主机,这最终停止工作,我有问题创build我们的项目依赖的符号链接。 所以我转而在Ubuntu VM中使用git,然后使用相同的bash脚本启动Ubuntu中的所有内容。

这个缺点是我基本上是在一个虚拟机编码,并不能在Windows中使用我的偏好的IDE。 这并不可怕,但在虚拟现实中工作并不理想,imo。

这个设置还有很多不足之处。 我们的小型开发团队花了几周的时间才使其处于可维护的状态。 工作stream程过程本来可以改进,但是既没有时间也没有知道如何…

我有兴趣听到其他人为Docker开发的工作stream程。

这终究是我解决的工作stream程。

build立开发环境的关键点:

  • 编写代码必须在docker外部进行
  • VCS必须在docker之外
  • 所有的编译和执行都应该在docker里面
  • Docker容器应该是无状态的,所以修改和创build一个新的docker容器只需要重新编译,执行

正如lighta所build议的,有两种select:

  1. 每项服务都有一个docker工人
  2. 一个泊坞窗内的所有服务

我更喜欢后一种方法,因为我在多个项目上工作,并且让mxndocker工人感觉比拥有mdocker工人差。

build立环境:

  • 从phusion_baseimage开始
  • 安装了mysql,phpmyadmin,nodejs,grunt和它的好友,apache,django
  • 设置init服务和日志logging(随着基本镜像随着runitsvlogd )启动apache,mysql等。 所以docker start会重启这些服务
  • 公开所需的端口(80,运行testing服务器通常为8000)
  • 现在,我以下面的方式定义我的挂载点
    • ~/host/projectDocker/src > /root/project
    • ~/host/projectDocker/dbData/mysql_data > /var/lib/mysql
    • ~/host/projectDocker/apache_conf > /etc/apache/sites-enabled/

到目前为止,这已经非常成功。 每当我们有一些特定的库或依赖项需要安装(特别是Haskell说),我们只是设置一个新的形象,并要求所有的开发商拉最新的形象和重build他们的容器。 瞧!

所有的冰雹docker。

这是我为我的nodejs应用程序做的。

首先有一个Dockerfile作为源代码的一部分,它看起来像这样

 FROM node:0.10-onbuild EXPOSE 8080 COPY . /src 

这是用来build立一个图像:

 sudo docker build -t myapp . 

一旦build立,我然后开发我的代码,并使用以下来查看我的容器中的更改:

 sudo docker run --rm -it -p 8080:8080 --name="myapp" -v '/path/to/app/src:/usr/src/app' myapp:latest 

注意-v这里我正在安装我的本地目录到容器中,所以我不需要重新编译每次我改变代码。

代码由githubpipe理,所以开发stream程是一样的。 做分支,在本地工作,一旦准备好合并回主。

如果我的应用程序依赖于另一个服务,比如说rabbitmq,我添加这是一个单独的docker容器,并为我的应用程序使用configuration文件。

希望这是有帮助的