1. 程式人生 > >使用docker高效搭建開發環境

使用docker高效搭建開發環境

搭建開發環境 docker

作為一個平時喜歡折騰的開發人員,我喜歡嘗試各種環境,使用感興趣的各種開源軟件。

同時,我也是有一些相對的小潔癖,很喜歡linux中權限最小化原則,我也不喜歡自己的環境中有太多不知道的東西。

做了多年的web開發,我接觸到的環境大致如下:

  1. 操作系統從centos5到centos7;

  2. webserver從apache到nginx;

  3. 開發語言從最初的php5.2到php7,又到現在主要使用Go,馬上還會開始接觸C++;

  4. 數據庫從mysql5.1到現在的5.7,前陣子又開始折騰mariadb;

  5. cache選型從memcache到redis;

  6. 隊列用過kafka,去年開始大量使用nsq;

公司雖然有專門負責部署、運維這些服務的同學,但我在開發的時候,還是喜歡自己來搭建這些東西,因為這樣通常可以對使用到的服務有更多的認識,也能幫助自己使用的更好。

今天我就來和大家分享下我是如何高效的搭建好自己的開發環境的。

搭建前說明

這裏先說明一點,對每個開源軟件,我幾乎都是自己編譯部署的,而不會使用類似yum install這種方式,也很少直接下載官方編譯好的二進制包,這都是為了能多深入了解用到的開源軟件。

但一些依賴的動態庫文件,如zlib等,還有編譯工具,如gcc、make等,我都是通過方便的yum install這種方式直接安裝的,否則會累死。

傳統做法

我在很長的一段時間內,都是把每個軟件的編譯、安裝過程寫成一個腳本,之後再需要用的時候直接運行腳本即可,但這樣的方式,通常會遇到下面這些問題:

  1. 腳本只能在我當時的操作系統環境下運行。記得當時購買過不同服務商的vps,雖然不同vps我都使用同樣的linux發行版,但腳本通常都不能一鍵跑完。這也是沒辦法,因為每個vps服務商都會制作自己的操作系統鏡像版本。

  2. 操作系統升級,如centos5 - 6,或是換為ubuntu,這樣基本上腳本都跑不了。

  3. 軟件升級,如mysql5.2 - 5.6,構建工具改為cmake,依賴庫改變或升級。

  4. 如果某個軟件依賴的公共庫版本和其它軟件不同,且公共庫升級後和舊版不兼容,那你就只能為這個軟件單獨編譯公共庫了,如果只是普通的公共庫還好,但如果是所需要的編譯工具版本不同,那可就慘了。

上面這些問題,如果你想每個發行版維護一個腳本,那會累死,因為一旦你每次想升級一個軟件,難道每個發行版都要編譯一遍嗎?這就變成了收獲價值很低的體力勞動了。

由於喜歡折騰的個性,我對操作系統的升級以及軟件包版本的升級又經常發生,所以一直以來,我都在尋找一個好方法,能很方便的維護好自己的開發環境,盡量做到只=新東西只為它工作一次,最後我找到了docker,目前我都是用它來搭建自己的開發環境的。

docker做法

先概括介紹下我的方法:

  1. 讓每個軟件運行在容器中,因為運行的容器環境是可以固定下來的,所以編譯安裝腳本寫一個就可以了。

  2. 代碼使用數據卷的方式加載到需要的容器中。

  3. 因為是開發環境,所以網絡方面使用最簡單的--net=host

  4. 將鏡像的創建、容器的啟動維護在git項目中,並抽象出統一的構建過程,很方面的做到新軟件接入,新機器部署。

下面用實例來說明把:

示例Nginx環境構建

我將構建過程放到git中:https://gitee.com/andals/docker-nginx

Readme中記錄了構建所需要執行的腳本命令,大家訪問上面的網址就可以看到,這裏我簡單介紹下項目的結構:

├── Dockerfile        //創建鏡像的Dockerfile├── pkg               //編譯好的二進制包,可以直接使用,此外軟件運行的一些配置文件或第三方包也放在這裏│   ├── conf
│   │   ├── fastcgi.conf
│   │   ├── http.d
│   │   ├── include│   │   ├── koi-utf
│   │   ├── koi-win
│   │   ├── logrotate.conf
│   │   ├── logrotate.d
│   │   ├── mime.types
│   │   ├── nginx.conf
│   │   ├── scgi_params
│   │   ├── uwsgi_params
│   │   └── win-utf
│   ├── luajit-2.0.3.tar.gz
│   └── nginx-1.8.1.tar.gz
├── README.md
├── script                //裏面放構建腳本│   ├── build_image.sh    //構建鏡像使用│   ├── build_pkg.sh      //編譯軟件包時使用│   ├── init.sh           //容器啟動時執行│   └── pre_build.sh      //軟件依賴的共享庫,編譯和構建時都會用到└── src                   //編譯時需要的軟件源碼
    ├── modules
    │   ├── ngx_devel_kit-0.2.19.tgz
    │   ├── ngx_echo-0.53.tgz
    │   └── ngx_lua-0.9.7.tgz
    ├── nginx-1.8.1.tar.gz
    └── openssl-1.0.2h.tar.gz

DockerFile說明

Dockerfile結構如下:

FROM andals/centos:7MAINTAINER ligang <[email protected]>

LABEL name="Nginx Image"LABEL vendor="Andals"COPY pkg/ /build/pkg/
COPY script/ /build/script/

RUN /build/script/build_image.sh

CMD /build/script/init.sh

整個構建框架為:

  1. 把構建需要的包(pkg目錄中)放到鏡像中

  2. 把構建腳本放到鏡像中

  3. 執行構建腳本

  4. 容器啟動時,執行init.sh,裏面啟動相應的服務

Readme.md中記錄了執行構建的命令和容器運行命令,示例運行如下:

ligang@vm-xubuntu16 ~/devspace/dbuild $ git clone [email protected]:andals/docker-nginx.git nginx
Cloning into 'nginx'...
......

ligang@vm-xubuntu16 ~/devspace/dbuild $ cd nginx/
ligang@vm-xubuntu16 ~/devspace/dbuild/nginx $ ngxVer=1.8.1ligang@vm-xubuntu16 ~/devspace/dbuild/nginx $ docker build -t andals/nginx:${ngxVer} ./
ligang@vm-xubuntu16 ~/devspace/dbuild/nginx $ docker build -t andals/nginx:${ngxVer} ./
Sending build context to Docker daemon   30.7MB
Step 1/8 : FROM andals/centos:7......
Successfully built ea8147743031
Successfully tagged andals/nginx:1.8.1ligang@vm-xubuntu16 ~/devspace/dbuild/nginx $ docker run -d --name=nginx-${ngxVer} --volumes-from=data-home -v /data/nginx:/data/nginx --net=host andals/nginx:${ngxVer}
dbf3c0617eb34c4b1b4ea54c2961989612d5474db3b1acd1d717221e6e5cb516

說明:

  • --volumes-from=data-home這個就是我放置代碼的數據卷,我喜歡把代碼放到$HOME下面,所以這個卷的相關信息如下:

ligang@vm-xubuntu16 ~ $ docker ps -a
CONTAINER ID        IMAGE                    COMMAND                  CREATED             STATUS                   PORTS               NAMES578912a08ea7        andals/centos:7          "echo Data Volumn Ho…"   9 days ago          Exited (0) 9 days ago                        data-home
......

ligang@vm-xubuntu16 ~ $ docker inspect 578912a08ea7
......        "Mounts": [
            {                "Type": "bind",                "Source": "/home",                "Destination": "/home",                "Mode": "",                "RW": true,                "Propagation": "rprivate"
            }
......
  • /data/nginx中放置nginx的conf、log等,每個軟件運行時的conf、log、data等我都統一放置在/data下面,如:

ligang@vm-xubuntu16 ~ $ tree -d /data/ -L 1/data/
├── mariadb
├── nginx
└── redis

ligang@vm-xubuntu16 ~ $ tree -d /data/nginx/
/data/nginx/
├── conf
│   ├── http.d
│   ├── include
│   └── logrotate.d
└── logs
  • 啟動容器時使用--net=host,作為開發環境簡單實用

我就是通過這種方法完成了開發環境的構建,不再有多余的重復工作,並且新機器部署開發環境效率極高。

我目前用到的容器環境如下:

ligang@vm-xubuntu16 ~ $ docker ps -a
CONTAINER ID        IMAGE                    COMMAND                  CREATED             STATUS                   PORTS               NAMES
dbf3c0617eb3        andals/nginx:1.8.1       "/bin/sh -c /build/s…"   33 minutes ago      Up 33 minutes                                nginx-1.8.13e31ef433298        andals/php:7.1.9         "/bin/sh -c /build/s…"   8 hours ago         Up 8 hours                                   php-7.1.9360f94bf9c43        andals/jekyll:latest     "/bin/sh -c /build/s…"   9 days ago          Up 10 hours                                  jekyll-latest
0a7d58d1ca5e        andals/redis:4.0.8       "/bin/sh -c /build/s…"   9 days ago          Up 10 hours                                  redis-4.0.8fdaa655b4a11        andals/samba:4.4.16      "/bin/sh -c /build/s…"   9 days ago          Up 10 hours                                  samba-4.4.166ad00a69befd        andals/mariadb:10.2.14   "/bin/sh -c /build/s…"   9 days ago          Up 10 hours                                  mariadb-10.2.14578912a08ea7        andals/centos:7          "echo Data Volumn Ho…"   9 days ago          Exited (0) 9 days ago                        data-home

輔助工具dockerbox

使用docker環境後,有個問題,就是沒有辦法很方便的和軟件交互。

這是因為軟件都執行在容器中,比如重啟nginx吧,需要下面這幾步:

  1. 找到nginx這個容器

  2. 進入nginx這個容器

  3. 在容器裏面再執行reload

也可以是:

  1. 找到nginx這個容器

  2. 使用docker exec

但無論哪種方式,都比原先直接執行命令麻煩的多。

另外,有時也需要進入容器中,查看服務的運行情況。

為了方便的做這些事情,我開發了一個工具dockerbox,可以很方便的做到這些事情。

dockerbox的詳情及使用方法請見:https://github.com/ligang1109/dockerbox

配置開機運行

最後再說下如何配置開機啟動。

我使用虛擬機搭建的開發環境,所以配置這個會省事好多,我使用用了systemd

ligang@vm-xubuntu16 ~ $ ll /lib/systemd/system/dstart.service
-rw-r--r-- 1 root root 229 4月   3 21:35 /lib/systemd/system/dstart.service

ligang@vm-xubuntu16 ~ $ cat /lib/systemd/system/dstart.service
[Unit]
Description=Docker Container Starter
After=network.target docker.service
Requires=docker.service

[Service]
ExecStart=/usr/local/bin/dbox -dconfPath=/home/ligang/.dconf.json start all

[Install]
WantedBy=multi-user.target

dbox請參考dockerbox的使用方法。

結束語

上面說的是我現在使用的開發環境搭建方法,有興趣愛折騰的同學不妨試試看,如果你有更好的方法,也希望能分享給我。

生命不息,折騰不止。

使用docker高效搭建開發環境