譯者按:在本專欄的前面的文章中,咱們已經提到過使用 Docker 的基本方法,所以本次講解一下 使用 SSH 和 shell 腳本進行 Docker 鏡像的自動化部署,原文僅供參考,由於對於 Docker 鏡像,咱們能夠有更好的解決方案:Docker Registry Hub。可是,本文仍然能夠做爲 shell 腳本的參考範例。程序員
當咱們將本站轉移到 Docker 容器內以後,我一直在尋求能進行自動化構建和部署鏡像的方法。毫無疑問,Docker 自己是一個很是完美的應用容器,可是 Docker 並無提供可以自動化更新鏡像的標準方法。固然,我寫了一些 shell 腳本,實現了 Docker 容器鏡像的自動化部署。web
咱們假設基礎架構是一臺 Linux 宿主機和幾個獨立的 Docker 鏡像,沒有網站運行時產生的動態文件,例如用戶上傳的文件。
固然,要解決這些動態文件也很是簡單,本篇文章中的腳本只須要修改一小部分,而後加上 data only container 即可以完美解決動態文件的問題。docker
那麼,咱們開始進行自動化部署吧。shell
腳本的初衷很是簡單:構建鏡像,上傳鏡像,使用新鏡像重啓容器。咱們會分段講解腳本,固然你只須要把本文的腳本段落組合起來,即可以執行自動化部署了。apache
假設咱們的 apache 文件在 apache/ 子目錄,一個監控程序在 monitoring/ 子目錄。bash
假設咱們的腳本名稱爲 deploy.sh
,使用以下命令進行初始化:服務器
#!/bin/bash set -e REMOTE_USERNAME="..." REMOTE_HOST="..." IMAGE_REPOSITORY="my_repository"
前面兩個變量並不須要解釋,後面上傳鏡像的時候用的到。
最後一個變量是 Docker 鏡像的名稱,你須要設置本身的鏡像名稱,在後面咱們也會有這個名稱進行檢測。架構
再後文中咱們會創建同一個名稱可是 tag 不一樣的兩個鏡像分別存儲 apache 和 monitor。ssh
第一件要作的事情即是構建鏡像,構建過程和普通的 Docker 命令同樣。咱們寫了一個函數專門用來構建鏡像:函數
function build_image { docker build -t $IMAGE_REPOSITORY:$1 $2 } build_image apache apache/ build_image monitoring monitoring/
咱們使用上面的已經定義的 IMAGE_REPOSITORY
名稱命名鏡像,而且對咱們的兩個 apache 和 monitoring 鏡像貼標籤。
固然本專欄的前文中提到,鏡像能夠輸出到文件,也能夠由文件輸入。固然也能夠從標準輸入輸出流進行輸入輸出。咱們使用標準輸入輸出流和管道進行操做。這個輸入和上傳的操做很容易用一行 shell 語句寫出來。
docker save $IMAGE_REPOSITORY:$1 | bzip2 | pv | ssh $REMOTE_USERNAME@$REMOTE_HOST 'bunzip2 | docker load'
固然,成熟的程序員都會寫個函數,順便作作重複性檢測,畢竟幾百 M 的文件呢,上傳都要很久,還能節省帶寬。尤爲是有不少鏡像須要上傳的時候,萬一有幾個重複的呢。咱們所須要的就是按照鏡像名稱和標籤列出本機和遠程服務器上的 Docker 容器的 ID,而後檢測他們的 ID 是否相同。
本節的 shell 腳本以下。
function upload_image_if_needed { if [[ $(ssh $REMOTE_USERNAME@$REMOTE_HOST "docker images $IMAGE_REPOSITORY | grep $1 | tr -s ' ' | cut -d ' ' -f 3") != $(docker images $IMAGE_REPOSITORY | grep $1 | tr -s ' ' | cut -d ' ' -f 3) ]] then echo "$1 image changed, updating..." docker save $IMAGE_REPOSITORY:$1 | bzip2 | pv | ssh $REMOTE_USERNAME@$REMOTE_HOST 'bunzip2 | docker load' else echo "$1 image did not change" fi } upload_image_if_needed apache upload_image_if_needed monitoring
上面說的是更新鏡像,本節講的是更新容器。
如今是最後一步,咱們須要使用新鏡像重啓容器。固然,和其餘的語言同樣,咱們能夠將遠程主機上的命令寫成本機上的輸入形式:
ssh -tt $REMOTE_USERNAME@$REMOTE_HOST << EOF ... exit EOF
而後判斷容器是否存在,若是存在就結束容器。
docker rm -f ${IMAGE_REPOSITORY}_apache || true docker rm -f ${IMAGE_REPOSITORY}_monitoring || true
注:可能有讀者對 docker rm -f ${IMAGE_REPOSITORY}_apache
這條命令感到不解,在此解釋一下。原文做者使用制定名稱 ${IMAGE_REPOSITORY}_apache
對容器進行命名。
||
是必需的,由於若是容器不存在的話,docker rm
命令便會返回一個錯誤。咱們只須要刪除容器,並不去判斷他們是否存在。不存在的也就不用刪除,固然,刪除也沒問題。
下面一步即是啓動容器:
docker run -d --name ${IMAGE_REPOSITORY}_apache $IMAGE_REPOSITORY:apache docker run -d --name ${IMAGE_REPOSITORY}_monitoring $IMAGE_REPOSITORY:monitoring
爲了便於閱讀,我特地整理了全部腳本的徹底版,以下:
#!/bin/bash set -e REMOTE_USERNAME="..." REMOTE_HOST="..." IMAGE_REPOSITORY="my_repository" function upload_image_if_needed { if [[ $(ssh $REMOTE_USERNAME@$REMOTE_HOST "docker images $IMAGE_REPOSITORY | grep $1 | tr -s ' ' | cut -d ' ' -f 3") != $(docker images $IMAGE_REPOSITORY | grep $1 | tr -s ' ' | cut -d ' ' -f 3) ]] then echo "$1 image changed, updating..." docker save $IMAGE_REPOSITORY:$1 | bzip2 | pv | ssh $REMOTE_USERNAME@$REMOTE_HOST 'bunzip2 | docker load' else echo "$1 image did not change" fi } function build_image { docker build -t $IMAGE_REPOSITORY:$1 $2 } build_image apache apache/ build_image monitoring monitoring/ upload_image_if_needed apache upload_image_if_needed monitoring ssh -tt $REMOTE_USERNAME@$REMOTE_HOST << EOF docker rm -f ${IMAGE_REPOSITORY}_apache || true docker rm -f ${IMAGE_REPOSITORY}_monitoring || true docker run -d --name ${IMAGE_REPOSITORY}_apache $IMAGE_REPOSITORY:apache docker run -d --name ${IMAGE_REPOSITORY}_monitoring $IMAGE_REPOSITORY:monitoring exit EOF
Docker 確實是容器中的佼佼者,並且有很好的命令行支持,可是目前仍是缺乏能便捷部署 Docker 容器的方式。固然,經過幾段簡單的腳本,咱們即可以解決這個問題。我但願這些腳本也能幫助到你。
本文對容器的操做比較簡單粗暴,使用 docker rm
命令進行強行刪除,可能會致使一段時間(通常不到半分鐘,視狀況而定)的網站 403,404 或者 503。
除此以外,本文的 shell 操做能夠當成是 shell 遠程執行命令的範例。
本專欄將繼續推出 Docker 系列文章,歡迎關注。