細說Mammut大數據系統測試環境Docker遷移之路
歡迎訪問網易雲社區,了解更多網易技術產品運營經驗。
前言
最近幾個月花了比較多精力在項目的測試環境Docker遷移上,從最初的docker“門外漢”到現在組裏的同學(大部分測試及少數的開發)都可以熟練地使用docker環境開展測試工作,中間也積累了一些經驗和踩過不少坑,借此2017復盤的機會,總結一下整個環境的搭建過程,希望可以給其他有誌於向docker遷移的項目提供些許參考,同時也想跟其他docker的老司機們一起探討改進方式。
Docker遷移的必要性
這篇文章不對docker的基本概念和基本使用進行細講,網上也有非常多關於docker的資料供大家參考。如果是對docker非常陌生的讀者,建議可以自己google一下docker的入門資料,或者推薦大家看一下《第一本Docker書》,可以對docker有一個基本的概念和了解。
但是展開全篇介紹之前,我還是想簡單介紹下“Docker遷移的必要性”,記得許家滔在《微服務在微信的架構實踐》一文中提過:“技術的演進來源於業務的需求”(原話記不太清了,大致是這樣),任何技術的改進不會是無端進行的。
從我們的大數據測試團隊來看:
測試人員增加
隨著網易猛獁技術團隊業務線和人員的擴張,我們的測試人員從之前的2-3個已經增長到了現在的7-8個,未來是否會繼續擴張不得而知。
測試類型豐富
從最初的僅有功能測試保障,到現在自動化測試、異常測試、穩定性測試、性能測試、tpcds兼容性/基準測試多種類型同步鋪開。
多版本並行開展
隨著產品方“對外私有化部署”和“內部版本開發”兩條線的同時推進,我們經常會面臨需要多版本同步測試的處境,而且後端組件可能同時需要測試“社區版本”和“內部開發版本”兩個版本。
伴隨著上述三方面的影響,而我們有且僅有一套測試環境。在測試過程中,經常會出現某一個人在執行測試活動時,其他測試人員被block,需要等待其執行完成後,再開始自己的測試,而且測試執行時不能被其他人影響的情況。此外,最近的一個版本上線後,出現了一個線上問題是跟“跨集群”業務有關的功能,而這一塊在上線前不論是開發還是測試都是沒有測試過的,因為無論是測試還是開發,我們都只部署了一套集群,沒有辦法進行跨集群的測試,僅通過開發的Code Review來保證上線。
至於為什麽我們不再多部署幾套測試環境呢?大數據整套系統非常的龐大,下面是我簡單羅列的大數據組件的種類(可能會有遺漏):
1. Mammut:Webserver、Executor、Redis Server、MySQL 2. Azkaban:Az-FC、Az-Webserver、Az-Executor、MySQL 3. Hadoop-Meta:Scheduler RPC、Service、KDC-RPC、MySQL 4. Kerberos:KDC Server、Kadmin、Kerberos Client 5. LDAP:Client、LDAP Server、LdapAdmin Server 6. Hive:HiveServer2、Hive Metastore、Hive Client、MySQL 7. Spark:Spark History Server、Spark Thrift Server、Spark Client 8. Ranger:RangerAdmin、MySQL 9. HDFS:NameNode、DataNode、JournalNode、HDFS Client、ZKFailoverController 10. YARN:ResourceManager、NodeManager 11. MapReduce:MapReduce History Server、MapReduce Client 12. ZooKeeper:Zookeeper Server、Zookeeper Clinet 13. Ambari:Ambari Server、Ambari Agent、MySQL 14. Hbase:待補充 15. Impala:待補充
組件的種類大致有15類,每個組件各自有自己的多個服務需要部署,並且其中大部分(80%以上)的服務都是集群式地多節點部署以支持高可用/負載均衡。從我們測試環境的Ambari管理頁面上看下我們具體部署的組件數量:
可以看到集成Ambari的“進程”級別的組件數量已經總計多達106個,還不包括其它未集成ambari的組件,如hadoop-meta、ldap、hbase、impala等等。
上述介紹的是猛獁系統的組件規模,而部署一套系統的成本到底有多大?記得在我們第一次進行私有化部署演練的時候,當時還沒有使用ambari,項目組讓每個開發、運維事先整理好自己所要部署的組件的詳細操作記錄,然後十來個開發加運維一起坐在“小黑屋”,部署了三天,沒有部署成功。更不用說,部署完成後,投入使用過程中的環境維護成本。如果離開ambari,相信沒有多少人敢獨自去部署一套猛獁系統。
在“環境亟待擴張”和“環境搭建維護成本巨大”的矛盾對立下,將測試環境向docker遷移的思路應運而生,docker的引進可以很好地解決我們的困境。
下面開始進入正題,介紹整個測試環境向Docker遷移演化的過程。主要包含的內容如下:
基於Ambari的容器鏡像制作
基於Swarm的容器雲搭建
跨雲主機的容器私有網絡組建和容器內部通信
支持多套環境的容器管理和組網方案
基於鏡像的環境自動部署
Rancher——集群環境的監控和管理
1.基於Ambari的容器鏡像制作
首先介紹下鏡像的制作過程。大家都知道,docker的鏡像制作有兩種方式:
(1)基於容器的commit (2)基於Dockerfile的構建
從Docker官方的推薦和業界大量的實踐證明,Dockerfile是更好的鏡像制作方式,它從一個基礎鏡像開始,記錄所有的操作過程,以及workspace、環境變量、volumn卷掛載、端口映射等一系列的重要信息。並且,它是可重錄的,在任何安裝了docker的環境下,只要基於一份簡單的Dockerfile文件就可以構建出所要的鏡像。當鏡像發生更改時,也只需要修改部分內容,即可以完成新鏡像的構建。對於頻繁更新的鏡像來說,這絕對是一種最佳的實踐方式,因為從基礎鏡像到目標鏡像的所有操作一目了然,不會引入額外的冗余文件系統。
然而,在大數據組件的鏡像制作過程中,並沒有采用Dockerfile的方式,而是選擇了第一種commit的方式。這主要是因為前面介紹過了大數據組件規模的龐大,如果要為每個組件的每個服務去制作單獨的鏡像,可能需要制作上百個鏡像,並且,各個組件的服務之間存在著繁雜的依賴關系,不管是采取何種方式(組件間的依賴處理一般有兩種方式:1.手動地將服務的端口映射到宿主機的端口,依賴服務調被依賴服務所在宿主機的相應端口;2.借助編排工具,如compose、kubernetes等,創建service,處理service之間的關系),我覺得由我一個人在短時間內都是無法實現的,更不論你需要去詳細了解每個組件的單獨部署方式。
此外,因為我們的私有化部署環境和現有測試後端集群的搭建都是基於Ambari(大數據環境部署工具,可以通過ambari-server將眾多集成的大數據組件,批量部署到若幹臺安裝了ambari-agent的機器上)搭建的,如果我們脫離ambari去制作各個單獨的組件服務鏡像,即使最終組合到一起成功完成環境的搭建,那與我們現有的環境也是不相符的。
基於上述背景,我們采取了一種新的環境搭建思路:
(1)使用基礎鏡像(如debian7官方鏡像),先啟動一組容器(比如8個) (2)在其中一個容器上部署ambari-server,在每個容器上部署ambari-agent (3)使用Ambari Web將集成了ambari的大數據組件(如Hive、Azkaban、YARN、Zookeeper、Spark、HDFS、Mammut、Ranger、MapReduce等)部署到各個容器內部 (4)在各個容器內手動部署未集成ambari的組件(如Hadoop-meta、LDAP、Kerberos等) (5)執行docker commit將全部8個容器制作為“容器鏡像套件”
而容器間的通信方式,最容易實現的當然是借助端口映射,將容器內部端口映射到宿主機端口,通過訪問宿主機IP加端口的方式來通信。但是,ambari-web在配置各個組件服務的地址時,有一部分配置必須使用主機名的格式,不支持ip加host的方式。而且考慮到後續想要在多套環境中基於鏡像去快速部署,基於ip加端口的方式顯然會對擴展造成嚴重的阻礙,需要額外地編寫腳本去動態獲取對端服務的宿主機ip、映射端口,甚至可能在部署完成後需要對一些配置進行大量手動修改。
為了解決上述問題,在我們的鏡像制作過程中,采取了固定hostname的方式。為每個容器加上特定的hostname(mammut-qa-docker-1.server.org~mammut-qa-docker-8.server.org),這樣在任何需要配置服務依賴的地方,我們可以直接填寫對端服務的hostname。而容器之間的通信,我們為每套大數據環境,創建一個特定的私有網絡(network),將同一套環境的容器掛載到同一個特定網絡下,這樣每個容器會被分配到一個私有ip,同一個私有網絡下的私有ip之間是互通的。然後通過自動化腳本去修改每個容器內部的/etc/hosts文件,添加ip-hostname的映射到容器內部的路由列表中。
到此,介紹了基於ambari的鏡像制作思路和容器內部通信的方式。已經可以在一臺物理機器上,完成整套大數據環境的搭建。然而,在實踐過程中發現,整個容器的鏡像套件,文件“體積”非常地大:
整個鏡像套件占用的磁盤空間可達到70多G。對於一個新的機器,去下載70G的鏡像,顯然還是需要挺久的時間。通過對鏡像內部文件的分析,可以發現,鏡像中有一大部分的文件來自於ambari-web在部署組件過程中產生的日誌文件,存儲在各個容器內部的/var/log文件下,而這部分日誌其實並不是我們部署所必須的,完全可以不打進鏡像中。因此,通過將/var/log目錄以volumn卷方式掛載到宿主機磁盤中,重新制作鏡像,整個鏡像套件的“體積”大幅度縮小,約30G:
2.基於Swarm的容器雲搭建
上節介紹了容器鏡像的制作,已經可以在一臺物理機上完成整套環境的搭建。然而,對於我們大多數項目來說,物理機資源是非常奢侈和稀缺的,我們不太可能讓公司采購那麽多的高規格的物理機。相對來說,雲主機資源比較容易申請。目前通過“運維誇父系統”申請的雲主機的配置可以達到8核cpu、32G內存、掛載500G雲盤。顯然,這麽多的組件如果要全部部署在一臺雲主機上,暫不說該雲主機是否可以支持這麽多的進程資源,即使你部署成功,後續在執行任務的時候肯定會出現資源不足的場景,要知道你的機器要支持的可是YARN、HDFS等。所以,如何將多臺雲主機聯合起來組成一個容器雲,讓鏡像套件中的8個容器鏡像,分散地部署到不同的雲主機上,成為我們一個突破機器瓶頸的思路。
業界處理容器編排的主要工具有Kubernertes、Swarm、Mesos。從GitHub上的活躍度來說,Kubernetes是遠超其它二者。而且,沸沸揚揚的容器編排之爭最近也已經結束,Kubernetes成為了容器編排最佳實踐的典範,Docker官方也已經宣布在下一個企業版本開始支持Kubernetes。然而,通過對Kubernetes的調研,它非常依賴於嚴格的微服務的架構,通過yaml可以很容易處理好服務之間的關系,非常適合企業級應用的生產環境部署。而我們的環境,實際上是通過ambari將多個不同組件服務揉合到了一起,並沒有為每個組件去制作單獨的鏡像。組件之間的依賴配置還嚴格依賴於特定的主機名,從各個角度來看Kubernetes都不適用於我們的場景(當然我並不是反對使用k8s,其實我是很想使用k8s。但是要使用k8s的前提應該是需要為每個服務去制作單獨的鏡像,而不是雜糅在一起,可能需要去除ambari工具的使用,這需要更上層的架構師來推動。此處如果我的理解有偏差,希望k8s的前輩指出)。
而Swarm(官方原生支持),基於容器的調度,可以說是非常適合我們的場景。將多臺雲主機聯合成一個容器集群,通過swarm-manage將這批容器鏡像調度到不同的雲主機上,即可完成容器的部署。同時,如果環境中的雲主機出現資源不足的場景,我們可以很方便地添加新的機器,然後將環境部署到更多的雲主機上來實現動態擴容。
關於Swarm集群的搭建,官方的樣例中,服務發現使用的是Consul,其實Consul包含的功能Zookeeper都有。由於對Zookeeper更加熟悉,就使用了 Zookeeper來代替Consul做了服務發現後端(discovery backend)。
3.跨雲主機的容器私有網絡組建和容器內部通信
不同於Kubernetes其自身有健全的網絡機制,通過pod可以很好的管理service的網絡,Swarm並沒有提供任何容器間網絡的支持。所以,我們需要自己解決當容器被調度到多個不同的雲主機之後,它們之間的通信問題。
前面提到過,在一臺雲主機上,我們可以創建一個私有網絡,然後將8個容器全部掛載到該私有網絡下,讓它們各自擁有自己的私有ip,然後添加ip-hostname的映射,以支持通過hostname的方式互相通信。現在容器被分配到了不同的雲主機上,是否還可以創建這樣的私有網絡呢?
幸運的是,docker1.9版本之後,docker采用VXLAN的覆蓋網技術,原生地提供了對“跨宿主機組網”非常便利的支持。
這裏簡要介紹下跨主機組網的實現方式,對於實踐過程中遇到問題的同學可以再私下單獨探討 。
(1)部署服務發現後端,如Zookeeper (2)修改DOCKER_OPTS,加入-H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --cluster-advertise=eth1:2375 --cluster-store zk://zk_path,重啟docker進程 (3)創建overlay網絡 :docker network create -d overlay netzni (4)創建docker_gwbridge網橋: docker network create --subnet 192.168.48.0/20 --opt com.docker.network.bridge.name=docker_gwbridge --opt com.docker.network.bridge.enable_icc=false --opt com.docker.network.bridge.enable_ip_masquerade=true docker_gwbridge (5)創建容器加入網絡:docker run --net netzni {image} (6)將已經運行的容器加入網絡:docker network connect netzni {container}
其中第2步是將雲主機加入集群中,讓集群知道有哪些機器在集群中。-H tcp://0.0.0.0:2375是開啟通過tcp socket的方式訪問本機的docker進程,默認情況下本地的docker進程只有-H unix://var/run/docker.sock的方式,即只支持unix socket的方式訪問本地docker進程。而eth1,必須是你雲主機機房網ip對應的網卡。如果是debian8的系統,修改DOCKER_OPTS參數會出現不生效的問題,可以參見附錄中第1個問題的解答。
對於第4步,創建docker_gwbridge網橋,這個網橋的作用在跨主機容器網絡中的作用就相當於單主機容器網絡中的docker0網橋的作用,用於連通不同主機容器之間的通信網絡。
自此,我們又實現了在不同雲主機環境下的私有網絡的創建,仔細觀察容器內部的網絡可以看到:
每個容器內部有兩個虛擬網卡,eth0對應的就是私有網絡分配的私有ip,而eth1對應的就是docker_gwbridge網橋分配的ip。當兩個容器通過私有ip進行互相通信時,需要經過docker_gwbridge網橋的轉發。
類似地,當跨主機的容器部署完成後,我們也需要通過自動化腳本去預置每個容器內部的/etc/hosts文件,加上ip-hostname的映射。
4.支持多套環境的容器管理和組網方案
前面介紹了如何在多臺雲主機上搭建私有網絡以及部署容器。那麽當部署的環境逐漸增多時,我們如何去部署和管理多套不同的環境呢?答案還是Swarm。
Swarm提供了“Label”的功能,即可以給每個雲主機貼上相應的標簽。所有基於docker搭建的大數據環境,都加入到一個統一的Swarm集群,受同一個swarm-manage管理。對不同的機器,給它們貼上對應的標簽。比如我有一批新的機器,都給它們都貼上“onwner=hznizhifeng”的標簽,表明是用來部署我的一套測試環境。然後相對應地,創建一個overlay私有網絡networkl_hznizhifeng。在使用swarm-manange進行容器調度時,通過過濾地方式指定容器可以被調度的機器,以及指定容器需要加入的網絡名,如:
docker -H ${HOST} run -d -e constraint:owner==${OWNER} --net network_${OWNER} --name mammut-qa-docker-7-$OWNER ${REGISTRY}/mammut-qa-docker-7:${VERSION} ./startup.sh
可以看到,容器名字的命名也可以通過{OWNER}來進行區分。
5.基於鏡像的環境自動部署
在完成前期的環境搭建工作後,我們需要將整個部署過程整合成自動化腳本,以實現快速部署,並降低部署的門檻,使得任何測試人員都可以輕松地完成環境部署。
下面簡單列下幾個部署腳本的內容,其它項目使用時可以參考。
(1)debian_init.sh:完成新機器環境的初始化工作,包括安裝docker、給docker守護進程打上owner標簽、 掛載雲盤、加入docker swarm集群、創建docker_gwbridge網橋、創建docker私有網絡等。
(2)mammut-docker-service.sh:容器調度腳本,包含容器啟動、停止、鏡像提交等。
(3)reset_container_hosts.sh:修改容器內部的hosts文件,預置ip-hostname的映射關系。
(4)setup_hosts.py:python腳本,獲取各個容器與所被分配到的雲主機之間的映射信息
關於gitlab的權限,有興趣的可以私下popo聯系我開通訪問。
在自動化腳本編輯過程中,有幾個有意思的實現方式可以給大家介紹下:
(1)容器鏡像的拉取
從前文可以看到,我們即使使用了volumn卷對日誌文件進行掛載,但是鏡像套件“體積”依然有30G,如何提升拉取速度呢?我們可以在shell腳本裏,在腳本命令後增加“&”的方式,將該條拉取命令掛到後臺執行,以實現多線程拉取的方式提升拉取鏡像的速度,然後在後面加上“wait”命令,以等待所有線程執行完了再執行後續的命令。
docker -H ${HOST} run -d -e constraint:owner==${OWNER} --net network_${OWNER} --name mammut-qa-docker-7-$OWNER -h mammut-qa-docker-7.server.org -v /root/log/mammut-qa-docker7:/var/log -p3306:3306 -p8080:8080 --cap-add=ALL ${REGISTRY}/mammut-qa-docker-7:${VERSION} ./startup.sh & docker -H ${HOST} run -d -e constraint:owner==${OWNER} --net network_${OWNER} --name mammut-qa-docker-6-$OWNER -h mammut-qa-docker-6.server.org -v /root/log/mammut-qa-docker6:/var/log -p80:80 -p8042:8042 --cap-add=ALL ${REGISTRY}/mammut-qa-docker-6:${VERSION} ./startup.sh & docker -H ${HOST} run -d -e constraint:owner==${OWNER} --net network_${OWNER} --name mammut-qa-docker-1-$OWNER -h mammut-qa-docker-1.server.org -v /root/log/mammut-qa-docker1:/var/log -p18081:18081 -p10000:10000 -p50070:50070 ${REGISTRY}/mammut-qa-docker-1:${VERSION} ./startup.sh & docker -H ${HOST} run -d -e constraint:owner==${OWNER} --net network_${OWNER} --name mammut-qa-docker-2-$OWNER -h mammut-qa-docker-2.server.org -v /root/log/mammut-qa-docker2:/var/log -p19888:19888 ${REGISTRY}/mammut-qa-docker-2:${VERSION} ./startup.sh & docker -H ${HOST} run -d -e constraint:owner==${OWNER} --net network_${OWNER} --name mammut-qa-docker-3-$OWNER -h mammut-qa-docker-3.server.org -v /root/log/mammut-qa-docker3:/var/log -p8088:8088 ${REGISTRY}/mammut-qa-docker-3:${VERSION} ./startup.sh & docker -H ${HOST} run -d -e constraint:owner==${OWNER} --net network_${OWNER} --name mammut-qa-docker-4-$OWNER -h mammut-qa-docker-4.server.org -v /root/log/mammut-qa-docker4:/var/log -p8088:8088 --cap-add=ALL ${REGISTRY}/mammut-qa-docker-4:${VERSION} ./startup.sh & docker -H ${HOST} run -d -e constraint:owner==${OWNER} --net network_${OWNER} --name mammut-qa-docker-5-$OWNER -h mammut-qa-docker-5.server.org -v /root/log/mammut-qa-docker5:/var/log -p50070:50070 -p8042:8042 ${REGISTRY}/mammut-qa-docker-5:${VERSION} ./startup.sh & docker -H ${HOST} run -d -e constraint:owner==${OWNER} --net network_${OWNER} --name mammut-qa-docker-8-$OWNER -h mammut-qa-docker-8.server.org -v /root/log/mammut-qa-docker8:/var/log -p10001:10001 -p6080:6080 ${REGISTRY}/mammut-qa-docker-8:${VERSION} ./startup.sh & wait
(2)容器內部hosts文件預置ip-hostname的映射關系
當容器部署完成後,我們可以通過docker network inspect network_hznizhifeng的方式,來查看該私有網絡下各個容器所分配到的私有ip信息,該信息是一個json格式,通過對該json的解析,便可以得到每個hostname對應的ip地址。這邊用的是python的方式,解析腳本可以參考:
#!/usr/bin/python# -*- coding: utf-8 -*__author__ = ‘zni.feng‘import osimport sys reload (sys) sys.setdefaultencoding(‘utf-8‘)import jsonclass HostsParser: def __init__(self, owner): self.owner = owner self.network_info_file = ‘docker_network_%s‘ % owner self.network_info_dict = None self.ip_hosts_mapping = list() def get_network_info(self): if not self.network_info_dict: with open(self.network_info_file, ‘r‘) as f: self.network_info_dict = json.load(f)[0] return self.network_info_dict.copy() def get_ip_host_mapping(self): if not self.ip_hosts_mapping: network_info_dict = self.get_network_info() containers_dict = network_info_dict[‘Containers‘] for container in containers_dict.values(): ipv4 = container[‘IPv4Address‘].split(‘/‘)[0] hostname = container[‘Name‘][:container[‘Name‘].find(self.owner)-1] ip_hosts_mapping="{0} {1}.server.org".format(ipv4, hostname) self.ip_hosts_mapping.append(ip_hosts_mapping) return self.ip_hosts_mapping def save_hosts(self): ip_hosts_mapping = self.get_ip_host_mapping() open(‘hosts‘,‘w‘).write(‘%s‘ % ‘\n‘.join(ip_hosts_mapping))if __name__ == ‘__main__‘: if len(sys.argv) <2: print ‘USAGE: python setup_hosts.py [LABEL]‘ print ‘LABEL: hznizhifeng|hzzhangyongbang|hzzhangjun15|e.g.‘ sys.exit(1) owner = sys.argv[1] parser = HostsParser(owner) parser.save_hosts()
6.Rancher——集群環境的監控和管理
完成集群的自動部署後,我們的測試集群已經可以輕松的部署使用了。並且,通過swarm-manage也可以對集群的容器進行管理。但是,swarm並沒有提供集群的監控,以及沒有友好的管理頁面。自然而然,我們希望有一種類似Web頁面的方式,可以對集群進行監控和管理。
在對業界的一些集群監控工具進行了調研後,最終選擇了Rancher(http://rancher.com/)作為我們的集群管理工具。它可以跟Kubernetes、Swarm等都很好地兼容,並提供了ldap等權限管理的方式,和豐富的管理api。此外它的一大特色就是它的“鏡像應用商店”,就好像App Store一樣。
Rancher的架構跟Swarm類似,由一個rancher-manage,多個rancher-agent和一個mysql組成。其部署方式這裏不細講,大家可以參考下rancher的官方文檔,或者私下交流。
下面截兩張rancher界面的圖,看看是不是你想要的:
(1)Rancher機器管理頁面
(2)Rancher容器監控頁面
此外,我們還可以在Rancher頁面上進入集群中的任一容器,進行內部操作,截圖可見“3.跨雲主機的容器私有網絡組建和容器內部通信”這一節中的圖。
總結和展望
能耐著性子看完的,相信都是真的想使用docker進行環境遷移的“真愛粉”,以及願意指點迷津幫助我們繼續改進的老司機。
從目前的現狀來看,我覺得當前的docker環境基本滿足了我們測試的需要,但是從整個大數據系統的部署來說,肯定不是最佳實踐。我相信如果能將各個組件制作成單獨的鏡像,借用k8s的service理念,肯定是可以讓整個結構更加完善。
從版本升級和鏡像維護的角度來說,我們目前其實是比較痛苦的。因為沒有使用Dockerfile,我們需要基於已有的鏡像,不斷地疊加新的文件系統然後commit,中間勢必會引入冗余的操作影響容器的整個“體積”。因為沒有為每個服務制作單獨的鏡像,不容易實現單個服務鏡像的升級。目前,我們也只是人為地建立了一套“版本鏡像套件升級規範”,以一個版本為一個叠代的方式,統一升級全部的鏡像套件。
目前,我們所有的部署操作都是在後臺執行腳本的方式來完成自動部署。未來,我們可以基於我們已有的技術棧,搭建一個基於docker的測試平臺,來實現環境的自動部署、回收、擴容,以及基於大數據的特點,實現多類型數據源(如DDB、Oracle、SQLServer、MySQL、PostgreSQL等)的一鍵生成和自動化測試工作。
附錄
debian8系統/etc/default/docker配置沒生效的問題
(1)修改/etc/default/docker文件,用OPTIONS替代DOCKER_OPTS。如: OPTIONS="--insecure-registry registry.hz.netease.com -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock" (2)修改/lib/systemd/system/docker.service文件,加入EnvironmentFile,並在ExecStart中加入$OPTIONS EnvironmentFile=-/etc/default/docker ExecStart=/usr/bin/dockerd $OPTIONS -H fd:// (3)執行systemctl daemon-reload使之生效 (4)重啟docker守護進程: /etc/init.d/docker restart (5)ps -ef|grep docker 或 docker info 看配置是否生效
網易大數據為您提供網易猛獁等服務,歡迎點擊免費試用。
本文來自網易實踐者社區,經作者倪誌風授權發布。
相關文章:
【推薦】 clojure.spec庫入門學習
【推薦】 值得細讀!如何系統有效地提升Android代碼的安全性?
【推薦】 盤點大數據在遊戲行業中的應用
細說Mammut大數據系統測試環境Docker遷移之路