作業系統從CentOS 5到CentOS 7;
Web Server從Apache到Nginx;
開發語言從最初的PHP 5.2到PHP 7,又到現在主要使用Go,馬上還會開始接觸C++;
資料庫從MySQL 5.1到現在的5.7,前陣子又開始折騰MariaDB;
Cache選型從Memcache到Redis;
隊列用過Kafka,去年開始大量使用NSQ。
公司雖然有專門負責部署、運維這些服務的同學,但我在開發的時候,還是喜歡自己來搭建這些東西,因為這樣通常可以對使用到的服務有更多的認識,也能幫助自己使用的更好。今天我就來和大家分享下我是如何高效的搭建好自己的開發環境的。這裡先說明一點,對每個開源軟體,我幾乎都是自己編譯部署的,而不會使用類似yum install這種方式,也很少直接下載官方編譯好的二進位包,這都是為了能多深入了解用到的開源軟體。但一些依賴的動態庫文件,如zlib等,還有編譯工具,如GCC、make等,我都是通過方便的yum install這種方式直接安裝的,否則會累死。我在很長的一段時間內,都是把每個軟體的編譯、安裝過程寫成一個腳本,之後再需要用的時候直接運行腳本即可,但這樣的方式,通常會遇到下面這些問題:腳本只能在我當時的作業系統環境下運行。記得當時購買過不同服務商的VPS,雖然不同VPS我都使用同樣的Linux發行版,但腳本通常都不能一鍵跑完。這也是沒辦法,因為每個VPS服務商都會製作自己的作業系統鏡像版本。
作業系統升級,如CentOS 5 - 6,或是換為Ubuntu,這樣基本上腳本都跑不了。
軟體升級,如MySQL 5.2 - 5.6,構建工具改為CMake,依賴庫改變或升級。
如果某個軟體依賴的公共庫版本和其它軟體不同,且公共庫升級後和舊版不兼容,那你就只能為這個軟體單獨編譯公共庫了,如果只是普通的公共庫還好,但如果是所需要的編譯工具版本不同,那可就慘了。
上面這些問題,如果你想每個發行版維護一個腳本,那會累死,因為一旦你每次想升級一個軟體,難道每個發行版都要編譯一遍嗎?這就變成了收穫價值很低的體力勞動了。由於喜歡折騰的個性,我對作業系統的升級以及軟體包版本的升級又經常發生,所以一直以來,我都在尋找一個好方法,能很方便的維護好自己的開發環境,儘量做到只=新東西只為它工作一次,最後我找到了Docker,目前我都是用它來搭建自己的開發環境的。讓每個軟體運行在容器中,因為運行的容器環境是可以固定下來的,所以編譯安裝腳本寫一個就可以了。
代碼使用數據卷的方式加載到需要的容器中。
因為是開發環境,所以網絡方面使用最簡單的--net=host。
將鏡像的創建、容器的啟動維護在Git項目中,並抽象出統一的構建過程,很方面的做到新軟體接入,新機器部署。
我將構建過程放到Git中:https://gitee.com/andals/docker-nginx。Readme中記錄了構建所需要執行的腳本命令,大家訪問上面的網址就可以看到,這裡我簡單介紹下項目的結構:├── 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
FROM andals/CentOS:7
MAINTAINER ligang <ligang1109@aliyun.com>
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
把構建需要的包(PKG目錄中)放到鏡像中
把構建腳本放到鏡像中
執行構建腳本
容器啟動時,執行init.sh,裡面啟動相應的服務
Readme.md中記錄了執行構建的命令和容器運行命令,示例運行如下:ligang@vm-xUbuntu16 ~/devspace/dbuild $ git clone git@gitee.com:andals/docker-Nginx.git Nginx
Cloning into 'Nginx'...
.
ligang@vm-xUbuntu16 ~/devspace/dbuild $ cd Nginx/
ligang@vm-xUbuntu16 ~/devspace/dbuild/Nginx $ ngxVer=1.8.1
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.1
ligang@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
ligang@vm-xUbuntu16 ~ $ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
578912a08ea7 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"
}
.
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
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.1
3e31ef433298 andals/php:7.1.9 "/bin/sh -c /build/s…" 8 hours ago Up 8 hours php-7.1.9
360f94bf9c43 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.8
fdaa655b4a11 andals/samba:4.4.16 "/bin/sh -c /build/s…" 9 days ago Up 10 hours samba-4.4.16
6ad00a69befd andals/mariadb:10.2.14 "/bin/sh -c /build/s…" 9 days ago Up 10 hours mariadb-10.2.14
578912a08ea7 andals/CentOS:7 "echo Data Volumn Ho…" 9 days ago Exited (0) 9 days ago data-home
找到Nginx這個容器
進入Nginx這個容器
在容器裡面再執行reload
為了方便的做這些事情,我開發了一個工具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