使用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:
- 每项服务都有一个docker工人
- 一个泊坞窗内的所有服务
我更喜欢后一种方法,因为我在多个项目上工作,并且让mxndocker工人感觉比拥有mdocker工人差。
build立环境:
- 从phusion_baseimage开始
- 安装了mysql,phpmyadmin,nodejs,grunt和它的好友,apache,django
- 设置init服务和日志logging(随着基本镜像随着
runit
和svlogd
)启动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文件。
希望这是有帮助的