摘要:Docker優(yōu)點(diǎn)已經(jīng)說(shuō)過(guò)很多次,這里不做詳述,Docker現(xiàn)在越來(lái)越受到開(kāi)發(fā)人員的青睞,而且利用Docker開(kāi)發(fā)的人也越來(lái)越多,本文來(lái)自Vidar Hokstad博客,他是一名Docker開(kāi)發(fā)人士,他總結(jié)了開(kāi)發(fā)Docker容器的8種模式。
【編者按】Vidar Hokstad 在Docker使用方面非常有經(jīng)驗(yàn),尤其在沒(méi)有數(shù)據(jù)丟失前提下,使用Docker創(chuàng)建可重復(fù)build上經(jīng)驗(yàn)豐富,在本博客中,他總結(jié)了開(kāi)發(fā)Docker容器的8種模式。
以下為譯文:
Docker現(xiàn)在成了我喜歡的工具,在本文中,我將概述一些在我使用Docker過(guò)程中反復(fù)出現(xiàn)的模式。我不期待它們能給你帶來(lái)多少驚喜,但我希望這些能對(duì)你有用,我非常愿意與你交流在使用Docker過(guò)程中碰到的模式。
我所有Docker實(shí)驗(yàn)的基礎(chǔ)是保持volume狀態(tài)不變,以便Docker容器在沒(méi)有數(shù)據(jù)丟失的前提下任意重構(gòu)。
下面所有的Dockerfiles例子都集中在:創(chuàng)建容器在其本身可以隨時(shí)更換的地方,而無(wú)需考慮其它。
1. The Shared Base Container(s)
Docker鼓勵(lì)“繼承”,這應(yīng)用也很自然——這是高效使用Docker的一個(gè)基本方式,不僅由于它有助于減少建立新容器的時(shí)間,Docker優(yōu)點(diǎn)多多,它會(huì)cache中間步驟,但也容易在不明確的情況下,失去分享機(jī)會(huì)。
很顯然,在將我的各種容器遷移到Docker上時(shí),首先要面對(duì)的是多個(gè)步驟。
對(duì)于多數(shù)想要隨處部署的項(xiàng)目來(lái)說(shuō)所,要?jiǎng)?chuàng)建多個(gè)容器,尤其是在這個(gè)項(xiàng)目需要長(zhǎng)進(jìn)程,或者需要特定包的情況,所以我要運(yùn)行的容器也變得越來(lái)越多。
重要的是為了讓mybase環(huán)境完全自由支配,我正考慮試圖在Docker上運(yùn)行“所有一切”(包括我依賴(lài)幾個(gè)桌面app)。
所以我很快開(kāi)始提取我的基本設(shè)置到base容器。這是我當(dāng)前的“devbase”Dockerfile:
FROM debian:wheezy
RUN apt-get update
RUN apt-get -y install ruby ruby-dev build-essential git
RUN apt-get install -y libopenssl-ruby libxslt-dev libxml2-dev
# For debugging
RUN apt-get install -y gdb strace
# Set up my user
RUN useradd vidarh -u 1000 -s /bin/bash --no-create-home
RUN gem install -n /usr/bin bundler
RUN gem install -n /usr/bin rake
WORKDIR /home/vidarh/
ENV HOME /home/vidarh
VOLUME ["/home"]
USER vidarh
EXPOSE 8080
這里沒(méi)有什么需要特別說(shuō)明的地方——它安裝一些需要隨時(shí)可用的特定工具。這些可能會(huì)對(duì)大多數(shù)人來(lái)說(shuō)是不同的。值得注意的是如果/當(dāng)你重建一個(gè)容器的時(shí)候,你需要指定一個(gè)特定的標(biāo)簽來(lái)避免意外。
使用默認(rèn)端口8080,因?yàn)檫@是我發(fā)布web app的端口,這也是我用這些容器的目的。
它為我添加了一個(gè)用戶(hù),并且不會(huì)創(chuàng)建一個(gè)/ home目錄。我從宿主機(jī)綁定掛載了一個(gè)共享文件夾/ home,這就引出了下一個(gè)模式。
2. The Shared Volume Dev Container
我所有的dev容器與宿主機(jī)分享至少一個(gè)volume: / home,這是為了便于開(kāi)發(fā)。對(duì)于許多app,在開(kāi)發(fā)模式中,使用基于file-system-change的code-reloader運(yùn)行,這樣一來(lái)容器內(nèi)封裝了OS / distro-level的依賴(lài),并在初始環(huán)境中幫助驗(yàn)證app-as-bundled工作,而不需要讓我每次在代碼改變時(shí)重啟/重建VM。
至于其他,我只需要重啟(而不是重建)容器來(lái)應(yīng)對(duì)代碼的更改。
對(duì)于test/staging和production容器,大多數(shù)情況下不通過(guò)volume共享代碼,轉(zhuǎn)而使用“ADD”來(lái)增添代碼到Docker容器中。
這是我的“homepage”的dev容器的Dockerfile,例如,包含我的個(gè)人wiki,存在于“devbase”容器中的 /home下,以下展示了如何使用共享的base容器和/home卷:
FROM vidarh/devbase
WORKDIR /home/vidarh/src/repos/homepage
ENTRYPOINT bin/homepage web
以下是dev-version的博客:
FROM vidarh/devbase
WORKDIR /
USER root
# For Graphivz integration
RUN apt-get update
RUN apt-get -y install graphviz xsltproc imagemagick
USER vidarh
WORKDIR /home/vidarh/src/repos/hokstad-com
ENTRYPOINT bundle exec rackup -p 8080
因?yàn)樗麄儚囊粋€(gè)共享的庫(kù)中取代碼,并且基于一個(gè)共享的base容器,這些容器通常當(dāng)我添加/修改/刪除依賴(lài)項(xiàng)時(shí)會(huì)極其迅速重建。
即便如此也有一些地方是我非常愿意改善,盡管上面的base是輕量級(jí)的,他們大多數(shù)在這些容器仍未使用。由于Docker使用copy-on-write覆蓋,這不會(huì)導(dǎo)致一個(gè)巨大的開(kāi)銷(xiāo),但它仍然意味著我沒(méi)有做到小的資源消耗,或者說(shuō)小化attack或error的幾率。
3. The Dev Tools Container
這可能對(duì)我們這些喜歡依靠ssh寫(xiě)代碼的人很有吸引力,但是對(duì)IDE人群則小一點(diǎn)。對(duì)我來(lái)說(shuō),關(guān)于以上設(shè)置更大的 一個(gè)好處,是它讓我在開(kāi)發(fā)應(yīng)用程序中,能夠?qū)⒕庉嫼蜏y(cè)試執(zhí)行代碼的工作分離開(kāi)來(lái)。
過(guò)去dev-systems對(duì)我來(lái)說(shuō)一件煩人的事,是dev和production依賴(lài)項(xiàng)以及開(kāi)發(fā)工具依賴(lài)項(xiàng)容易混淆,很容易產(chǎn)生非法的依賴(lài)項(xiàng)。
雖然有很多方法解決這個(gè),比如通過(guò)定期的測(cè)試部署,但我更偏愛(ài)下面的解決方案,因?yàn)榭梢栽跁r(shí)間防止問(wèn)題的發(fā)生:
我有一個(gè)單獨(dú)的容器包含Emacs的installation以及其他各種我喜歡的工具,我仍然試圖保持sparse,但關(guān)鍵是我的screen session可以運(yùn)行在這個(gè)容器中,再加上我筆記本電腦上的“autossh”,這個(gè)連接幾乎一直保持,在那里我可以編輯代碼,并且和我的其他dev容器實(shí)時(shí)共享。如下:
FROM vidarh/devbase
RUN apt-get update
RUN apt-get -y install openssh-server emacs23-nox htop screen
# For debugging
RUN apt-get -y install sudo wget curl telnet tcpdump
# For 32-bit experiments
RUN apt-get -y install gcc-multilib
# Man pages and "most" viewer:
RUN apt-get install -y man most
RUN mkdir /var/run/sshd
ENTRYPOINT /usr/sbin/sshd -D
VOLUME ["/home"]
EXPOSE 22
EXPOSE 8080
結(jié)合共享“/ home“,已經(jīng)足夠讓ssh的接入了,并且被證明能滿(mǎn)足我的需要。
4. The Test In A Different Environment containers
我喜歡Docker的一個(gè)原因,是它可以讓我在不同的環(huán)境中測(cè)試我的代碼。例如,當(dāng)我升級(jí)Ruby編譯器到1.9時(shí),我可以生成一個(gè)Dockerfile,派生一個(gè)1.8的環(huán)境。
FROM vidarh/devbase
RUN apt-get update
RUN apt-get -y install ruby1.8 git ruby1.8-dev
當(dāng)然你可以用rbenv等達(dá)到類(lèi)似的效果。但我總是覺(jué)得這些工具很討厭,因?yàn)槲蚁矚g盡可能多地用distro-packages部署,不僅僅是因?yàn)槿绻@項(xiàng)工作的順利進(jìn)行,能使其他人更容易地使用我的代碼。
當(dāng)擁有一個(gè)Docker容器,我需要一個(gè)不同的環(huán)境時(shí),我僅需要“docker run”一下,幾分鐘便能很好的解決這個(gè)問(wèn)題。
當(dāng)然,我也可以使用虛擬機(jī)來(lái)達(dá)到目的,但使用Docker更省時(shí)間。
5. The Build Container
這些天我寫(xiě)的代碼大部分都是解釋性語(yǔ)言,但還是有一些代價(jià)高昂的“build”步驟,我并不愿意每次都去執(zhí)行它們。
一個(gè)例子是為Ruby應(yīng)用程序運(yùn)行“bundler”。Bundler 為Rubygems更新被緩存的依賴(lài),并且需要時(shí)間來(lái)運(yùn)行一個(gè)更大的app。
經(jīng)常需要在應(yīng)用程序運(yùn)行時(shí)不必要的依賴(lài)項(xiàng)。例如安裝依賴(lài)本地?cái)U(kuò)展gems的通常還需要很多包——通常沒(méi)有記錄——通過(guò)添加所有build-essential和它的依賴(lài)項(xiàng)就輕松啟動(dòng)。同時(shí),你可以預(yù)先讓bundler做所有的工作,我真的不想在主機(jī)環(huán)境中運(yùn)行它,因?yàn)檫@可能與我部署的容器不兼容。
一個(gè)解決方案是創(chuàng)建一個(gè)build容器。如果依賴(lài)項(xiàng)不同的話,你可以創(chuàng)建分別的Dockerfile,或者你可以重用主app Dockerfile以及重寫(xiě)命令運(yùn)行你所需的build commands。Dockerfile如下:
FROM myapp
RUN apt-get update
RUN apt-get install -y build-essential [assorted dev packages for libraries]
VOLUME ["/build"]
WORKDIR /build
CMD ["bundler", "install","--path","vendor","--standalone"]
然后每當(dāng)有依賴(lài)更新時(shí),都可以運(yùn)行上面的代碼,同時(shí)將build/source目錄掛載在容器的"/build"路徑下。
6. The Installation Container
這不是我擅長(zhǎng)的,但是真的值得提及。的nsenter和docker-enter工具在安裝時(shí)有一個(gè)選項(xiàng),對(duì)于現(xiàn)在流行的curl | bash模式是一個(gè)很大的進(jìn)步,它通過(guò)提供一個(gè)Docker容器實(shí)現(xiàn)“Build Container”模式。
這是Dockerfile的后部分,下載并構(gòu)建一個(gè)nsenter的合適版本:
ADD installer /installer
CMD /installer
“installer”如下:
#!/bin/sh
if mountpoint -q /target; then
echo "Installing nsenter to /target"
cp /nsenter /target
echo "Installing docker-enter to /target"
cp /docker-enter /target
else
echo "/target is not a mountpoint."
echo "You can either:"
echo "- re-run this container with -v /usr/local/bin:/target"
echo "- extract the nsenter binary (located at /nsenter)"
fi
雖然可能還有惡意攻擊者試圖利用容器潛在的特權(quán)升級(jí)問(wèn)題,但是attack surface至少顯著變小。
這種模式能吸引大多數(shù)人,是因?yàn)檫@種模式能避免開(kāi)發(fā)人員在安裝腳本時(shí)偶爾犯的非常危險(xiǎn)的錯(cuò)誤。
7. The Default-Service-In-A-Box Containers
當(dāng)我認(rèn)真對(duì)待一個(gè)app,并且相對(duì)快速的準(zhǔn)備一個(gè)合適的容器來(lái)處理數(shù)據(jù)庫(kù)等,對(duì)于這些項(xiàng)目,我覺(jué)得難能可貴的是已經(jīng)有一系列的“基本的”基礎(chǔ)設(shè)施容器,只做適當(dāng)?shù)恼{(diào)整就可以滿(mǎn)足我的需求。
當(dāng)然你也可以通過(guò)“docker run”得到“主要的”部分,在Docker索引里有諸多替代品,但我喜歡首先檢查它們,找出如何處理數(shù)據(jù),然后我將修改版本添加到自己的“l(fā)ibrary”。
例如Beanstalkd:
FROM debian:wheezy
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get -q update
RUN apt-get -y install build-essential
ADD <a href="http://github.com/kr/beanstalkd/archive/v1.9.tar.gz">http://github.com/kr/beanstalkd/archive/v1.9.tar.gz</a> /tmp/
RUN cd /tmp && tar zxvf v1.9.tar.gz
RUN cd /tmp/beanstalkd-1.9/ && make
RUN cp /tmp/beanstalkd-1.9/beanstalkd /usr/local/bin/
EXPOSE 11300
CMD ["/usr/local/bin/beanstalkd","-n"]
8. The Infrastructure / Glue Containers
許多這些模式專(zhuān)注于開(kāi)發(fā)環(huán)境(這意味著有production 環(huán)境有待討論),但有一個(gè)大類(lèi)別缺失:
容器其目的是將你的環(huán)境組合起來(lái)成為一個(gè)整體,這是目前為止對(duì)我來(lái)說(shuō)有待進(jìn)一步研究的領(lǐng)域,但我將提到一個(gè)特殊的例子:
為了輕松地訪問(wèn)我的容器,我有一個(gè)小的haproxy容器。我有一個(gè)通配符DNS條目指向我的主服務(wù)器,和一個(gè)iptable入口開(kāi)放訪問(wèn)我的haproxy容器。Dockerfile沒(méi)什么特別的:
FROM debian:wheezy
ADD wheezy-backports.list /etc/apt/sources.list.d/
RUN apt-get update
RUN apt-get -y install haproxy
ADD haproxy.cfg /etc/haproxy/haproxy.cfg
CMD ["haproxy", "-db", "-f", "/etc/haproxy/haproxy.cfg"]
EXPOSE 80
EXPOSE 443
這里有趣的是haproxy.cfg
backend test
acl authok http_auth(adminusers)
http-request auth realm Hokstad if !authok
server s1 192.168.0.44:8084
如果我想要特別一點(diǎn),我會(huì)部署類(lèi)似 AirBnB's Synapse ,但這已經(jīng)超出了我的需求。
在工作時(shí)擴(kuò)大容器的規(guī)模,目的是讓部署應(yīng)用程序簡(jiǎn)單便捷,就像我正在過(guò)渡到一個(gè)完整的面向Docker的私有云系統(tǒng)。
原文鏈接: Eight Docker Development Patterns
本站文章版權(quán)歸原作者及原出處所有 。內(nèi)容為作者個(gè)人觀點(diǎn), 并不代表本站贊同其觀點(diǎn)和對(duì)其真實(shí)性負(fù)責(zé),本站只提供參考并不構(gòu)成任何投資及應(yīng)用建議。本站是一個(gè)個(gè)人學(xué)習(xí)交流的平臺(tái),網(wǎng)站上部分文章為轉(zhuǎn)載,并不用于任何商業(yè)目的,我們已經(jīng)盡可能的對(duì)作者和來(lái)源進(jìn)行了通告,但是能力有限或疏忽,造成漏登,請(qǐng)及時(shí)聯(lián)系我們,我們將根據(jù)著作權(quán)人的要求,立即更正或者刪除有關(guān)內(nèi)容。本站擁有對(duì)此聲明的最終解釋權(quán)。