經驗之談:八種Docker容器開發模式

jopen 10年前發布 | 27K 次閱讀 Docker

Docker優點已經說過很多次,這里不做詳述,Docker現在越來越受到開發人員的青睞,而且利用Docker開發的人也越來越多,本文來自Vidar Hokstad博客,他是一名Docker開發資深人士,他總結了開發Docker容器的8種模式。 Vidar Hokstad 在Docker使用方面非常有經驗,尤其在沒有數據丟失前提下,使用Docker創建可重復build上經驗豐富,在本博客中,他總結了開發Docker容器的8種模式。

以下為譯文:

Docker現在成了我最喜歡的工具,在本文中,我將概述一些在我使用Docker過程中反復出現的模式。我不期待它們能給你帶來多少驚喜,但我希望這些能對你有用,我非常愿意與你交流在使用Docker過程中碰到的模式。

我所有Docker實驗的基礎是保持volume狀態不變,以便Docker容器在沒有數據丟失的前提下任意重構。

下面所有的Dockerfiles例子都集中在:創建容器在其本身可以隨時更換的地方,而無需考慮其它。

1. The Shared Base Container(s)

Docker鼓勵“繼承”,這應用也很自然——這是高效使用Docker的一個基本方式,不僅由于它有助于減少建立新容器的時間,Docker優點多多,它會cache中間步驟,但也容易在不明確的情況下,失去分享機會。

很顯然,在將我的各種容器遷移到Docker上時,首先要面對的是多個步驟。




























對于多數想要隨處部署的項目來說所,要創建多個容器,尤其是在這個項目需要長進程,或者需要特定包的情況,所以我要運行的容器也變得越來越多。

重要的是為了讓mybase環境完全自由支配,我正考慮試圖在Docker上運行“所有一切”(包括我依賴幾個桌面app)。

所以我很快開始提取我的基本設置到base容器。這是我當前的“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

這里沒有什么需要特別說明的地方——它安裝一些需要隨時可用的特定工具。這些可能會對大多數人來說是不同的。值得注意的是如果/當你重建一個容器的時候,你需要指定一個特定的標簽來避免意外。

使用默認端口8080,因為這是我發布web app的端口,這也是我用這些容器的目的。

它為我添加了一個用戶,并且不會創建一個/ home目錄。我從宿主機綁定掛載了一個共享文件夾/ home,這就引出了下一個模式。

2. The Shared Volume Dev Container

我所有的dev容器與宿主機分享至少一個volume: / home,這是為了便于開發。對于許多app,在開發模式中,使用基于file-system-change的code-reloader運行,這樣一來容器內封裝了OS / distro-level的依賴,并在初始環境中幫助驗證app-as-bundled工作,而不需要讓我每次在代碼改變時重啟/重建VM。

至于其他,我只需要重啟(而不是重建)容器來應對代碼的更改。

對于test/staging和production容器,大多數情況下不通過volume共享代碼,轉而使用“ADD”來增添代碼到Docker容器中。

這是我的“homepage”的dev容器的Dockerfile,例如,包含我的個人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

因為他們從一個共享的庫中取代碼,并且基于一個共享的base容器,這些容器通常當我添加/修改/刪除依賴項時會極其迅速重建。

即便如此也有一些地方是我非常愿意改善,盡管上面的base是輕量級的,他們大多數在這些容器仍未使用。由于Docker使用copy-on- write覆蓋,這不會導致一個巨大的開銷,但它仍然意味著我沒有做到最小的資源消耗,或者說最小化attack或error的幾率。

3. The Dev Tools Container

這可能對我們這些喜歡依靠ssh寫代碼的人很有吸引力,但是對IDE人群則小一點。對我來說,關于以上設置更大的 一個好處,是它讓我在開發應用程序中,能夠將編輯和測試執行代碼的工作分離開來。

過去dev-systems對我來說一件煩人的事,是dev和production依賴項以及開發工具依賴項容易混淆,很容易產生非法的依賴項。

雖然有很多方法解決這個,比如通過定期的測試部署,但我更偏愛下面的解決方案,因為可以在第一時間防止問題的發生:

我有一個單獨的容器包含Emacs的installation以及其他各種我喜歡的工具,我仍然試圖保持sparse,但關鍵是我的screen session可以運行在這個容器中,再加上我筆記本電腦上的“autossh”,這個連接幾乎一直保持,在那里我可以編輯代碼,并且和我的其他dev容器實時共享。如下:

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

結合共享“/ home“,已經足夠讓ssh的接入了,并且被證明能滿足我的需要。

4. The Test In A Different Environment containers

我喜歡Docker的一個原因,是它可以讓我在不同的環境中測試我的代碼。例如,當我升級Ruby編譯器到1.9時,我可以生成一個Dockerfile,派生一個1.8的環境。

FROM vidarh/devbase
RUN apt-get update
RUN apt-get -y install ruby1.8 git ruby1.8-dev

當然你可以用rbenv等達到類似的效果。但我總是覺得這些工具很討厭,因為我喜歡盡可能多地用distro-packages部署,不僅僅是因為如果這項工作的順利進行,能使其他人更容易地使用我的代碼。

當擁有一個Docker容器,我需要一個不同的環境時,我僅需要“docker run”一下,幾分鐘便能很好的解決這個問題。

當然,我也可以使用虛擬機來達到目的,但使用Docker更省時間。

5. The Build Container

這些天我寫的代碼大部分都是解釋性語言,但還是有一些代價高昂的“build”步驟,我并不愿意每次都去執行它們。

一個例子是為Ruby應用程序運行“bundler”。Bundler 為Rubygems更新被緩存的依賴,并且需要時間來運行一個更大的app。

經常需要在應用程序運行時不必要的依賴項。例如安裝依賴本地擴展gems的通常還需要很多包——通常沒有記錄——通過添加所有 build-essential和它的依賴項就輕松啟動。同時,你可以預先讓bundler做所有的工作,我真的不想在主機環境中運行它,因為這可能與我部署的容器不兼容。

一個解決方案是創建一個build容器。如果依賴項不同的話,你可以創建分別的Dockerfile,或者你可以重用主app Dockerfile以及重寫命令運行你所需的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"]

然后每當有依賴更新時,都可以運行上面的代碼,同時將build/source目錄掛載在容器的"/build"路徑下。

6. The Installation Container

這不是我擅長的,但是真的值得提及。優秀的nsenter和docker-enter工具在安裝時有一個選項,對于現在流行的curl | bash模式是一個很大的進步,它通過提供一個Docker容器實現“Build Container”模式。

這是Dockerfile的最后部分,下載并構建一個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

雖然可能還有惡意攻擊者試圖利用容器潛在的特權升級問題,但是attack surface至少顯著變小。

這種模式能吸引大多數人,是因為這種模式能避免開發人員在安裝腳本時偶爾犯的非常危險的錯誤。

7. The Default-Service-In-A-Box Containers

當我認真對待一個app,并且相對快速的準備一個合適的容器來處理數據庫等,對于這些項目,我覺得難能可貴的是已經有一系列的“基本的”基礎設施容器,只做適當的調整就可以滿足我的需求。

當然你也可以通過“docker run”得到“主要的”部分,在Docker索引里有諸多替代品,但我喜歡首先檢查它們,找出如何處理數據,然后我將修改版本添加到自己的“library”。

例如Beanstalkd:

FROM debian:wheezy
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get -q update
RUN apt-get -y install build-essential
ADD <a >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

許多這些模式專注于開發環境(這意味著有production 環境有待討論),但有一個大類別缺失:

容器其目的是將你的環境組合起來成為一個整體,這是目前為止對我來說有待進一步研究的領域,但我將提到一個特殊的例子:

為了輕松地訪問我的容器,我有一個小的haproxy容器。我有一個通配符DNS條目指向我的主服務器,和一個iptable入口開放訪問我的haproxy容器。Dockerfile沒什么特別的:

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

如果我想要特別一點,我會部署類似 AirBnB's Synapse ,但這已經超出了我的需求。

在工作時擴大容器的規模,目的是讓部署應用程序簡單便捷,就像我正在過渡到一個完整的面向Docker的私有云系統。

原文鏈接: Eight Docker Development Patterns (編譯/魏偉 審校/周小璐)
來自:http://www.csdn.net/article/2014-10-27/2822294

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!