?從零開始Docker化你的Node.js應用

levy9527發表於2018-06-22

背景

給你一臺新買的伺服器(CentOS),相關賬戶及密碼,一個基於Node.js開發的web應用原始碼包(zip),要求你在新機器上使用Docker的方式把應用部署起來。此時的你,並沒有搞清楚什麼是容器/映象,也沒記住幾個相關的Linux命令,該怎麼辦?本文將幫助你擺脫困境

方案

流程

為達到最終目的,先來梳理一波流程:

  1. 把原始碼zip包上傳至伺服器

  2. 登入伺服器

  3. 解壓zip包

  4. 安裝最新Docker

  5. 設定國內映象加速器

  6. 編寫Dockerfile

  7. 構建映象

  8. 編寫啟動容器指令碼

  9. 執行指令碼,檢查部署情況

下面將詳細描述如何操作

文中伺服器作業系統為CentOS 7,如果你的伺服器不相符,操作細節可能會略有不同,需要另行查閱相關資料

rsync傳輸

假設:

  • 伺服器地址為${ip}

  • 帳戶為${user}

  • 密碼為${pass}

  • 原始碼包為${zip}

  • zip包放到伺服器的目錄為${path}

則在本機原始碼包同級目錄下,使用scp命令,把zip包傳輸至伺服器的示例如下

rsync -avzP ./${zip} ${user}@${ip}:${path}# 後面會提示輸入密碼複製程式碼

ssh登入

承接上文,ssh登入伺服器示例如下

ssh ${user}@${ip}# 後面會提示輸入密碼
# 第一次登入會提示儲存ssh資訊,輸入yes即可複製程式碼

如果不想每次都輸入地址/帳戶/密碼,可以寫一個簡單的自動登入指令碼ssh.sh

# 建立檔案
touch ssh.sh
# 賦予指令碼可執行權力
chmod +x ssh.sh複製程式碼

ssh.sh內容如下,記得把${pass}, ${user},${ip}替換為真實資料

#!/usr/bin/expect
set timeout 30
set password ${pass}
spawn ssh ${user}@${ip}
expect "*assword:"
send "$password\r"
interact複製程式碼

執行指令碼即可登入伺服器?

./ssh.sh複製程式碼

unzip解壓

如上所說,原始碼包名為${zip},解壓命令如下

unzip ${zip}複製程式碼

附帶一句, 如果要用命令生成zip包,假設原始檔目錄為dist,要生成的zip包為dist.zip, 其命令如下

zip -r dist.zip dist
# 或簡寫為
zip -r dist dist複製程式碼

安裝Docker-CE

CE意為Community Edition, 即社群版,免費; 與之對應的是EE,Enterprise Edition, 企業版,強調安全,付費使用。

  • 解除安裝舊版本的Docker

如果新機器上沒有docker,跳至下一步,直接安裝Docker的依賴

sudo yum remove docker \
                  docker-common \
                  container-selinux \
                  docker-selinux \
                  docker-engine \
                  docker-engine-selinux  複製程式碼
  • 安裝Docker的依賴

sudo yum install -y yum-utils device-mapper-persistent-data lvm2複製程式碼
  • 安裝Docker官方倉庫

sudo yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo複製程式碼
  • 更新倉庫源

sudo yum makecache fast複製程式碼
  • 從倉庫安裝Docker-CE

sudo yum install docker-ce複製程式碼

配置加速器

使用 Docker 的時候,需要經常從官方獲取映象,但是由於顯而易見的網路原因,拉取映象的過程非常耗時,嚴重影響使用 Docker 的體驗。

推薦使用DaoCloud的加速器

Dockerfile

所有環境配置已準備完畢,可以根據Node.js應用編寫Dockerfile了

假設Node.js應用的啟動命令為npm start, 監聽埠為${app_port}

  • 建立Dockerfile

touch Dockerfile複製程式碼

Dockerfile內容如下

# 可以指定依賴的node映象的版本 node:<version>,如果不指定,就會是最新的
FROM node:8
​
# 建立工作目錄,對應的是應用程式碼存放在容器內的路徑
WORKDIR /usr/src/app
​
# 把 package.json,package-lock.json(npm@5+) 或 yarn.lock 複製到工作目錄(相對路徑)
COPY package.json *.lock .
​
# 只安裝dependencies依賴
# node映象自帶yarn
RUN yarn --only=prod --registry=https://registry.npm.taobao.org
​
# 把其他原始檔複製到工作目錄
COPY . .
​
# 替換成應用實際的埠號
EXPOSE ${app_port}# 這裡根據實際起動命令做修改
CMD [ "npm", "start" ]複製程式碼
  • 補充.dockerignore

touch .dockerignore複製程式碼

.dockerignore內容如下

node_modules
npm-debug.log複製程式碼

構建映象

寫好Dockerfile,就可以在Dockerfile所在目錄構建映象了。

命令如下。-t是為了給映象加個標籤,這樣方便使用docker images命令時檢索到

# ${your_name} 可以省略
# ${tag} 省略時為 latest
docker build -t ${your_name}/${image_name}:${tag} .
​
# 省略版本
docker build -t ${image_name} .複製程式碼

檢視映象

docker images
​
# 示例輸出
REPOSITORY                      TAG        ID              CREATED
node                            8          1934b0b038d1    5 days ago
${your_name}/${image_name}    latest     d64d3505b0d2    1 minute ago複製程式碼

啟動容器指令碼

touch start.sh
chmod +x start.sh複製程式碼

start.sh會根據映象新建一個容器並啟動,內容如下

#!/usr/bin/env bash
​
container=${container_name}
image=${image_name || image_id}
​
docker run \
--rm \
-d \
-p ${host_port}:${app_port} \
--name $container \
$image複製程式碼

${host_port}是外網訪問部署好的應用時對應的埠

${app_port}是容器內Node.js應用監聽的埠

${image_name}是前面構建出的映象的名字,可用docker images檢視

${container_name}是給容器賦予的名字,方便docker ps命令時檢索

--rm 容器退出後隨之將其刪除

-d 後臺執行

-p 指定埠對映,前者是伺服器器埠,也即外界訪問你部署好的web應用的埠; 後者是DockerfileEXPOSE的埠

--name 指定容器名字

測試

訪問剛剛啟動的容器裡的應用

curl -i localhost:${host_port}# 示例輸出
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/html; charset=utf-8
...複製程式碼

恭喜,部署成功?

常用命令

  • 檢視執行中的容器

docker ps
# 或使用新命令
docker container ls
​
# 示例輸出
ID            IMAGE                                COMMAND    ...   PORTS
ecce33b30ebf  ${your_name}/${image_name}:latest  npm start  ...   49160->8080複製程式碼
  • 檢視所有容器(包括已終止的)

docker ps -a
# 或使用新命令
docker container ls -a複製程式碼
  • 檢視某容器內日誌

docker logs -f ${container_id}複製程式碼
  • 進入某容器,並有shell執行環境

# 進入容器
# -i表示:互動式操作,-t表示:終端
docker exec -it ${container_id} bash
# 可通過輸入 exit 退出 複製程式碼
  • 停止容器

docker container stop ${container_id}複製程式碼
  • 啟動已終止的容器

docker container start ${container_id}複製程式碼
  • 刪除容器

docker container rm ${container_name || container_id}複製程式碼
  • 檢視映象

docker images
# 或使用新命令
docker image ls複製程式碼
  • 刪除映象

docker image rm ${image_id}複製程式碼

FAQ

  • 不會vi,不懂怎麼在伺服器編輯Dockerfile等檔案,怎麼辦?

可以參考本文,把檔案在本地建立好,再通過scp把建立的檔案跟原始碼包一起上傳到伺服器

  • 為什麼使用yarn?

因為yarn的速度比npm更快,而docker裡的node映象自帶了yarn, 正好鼓勵大家使用yarn

  • 如果專案有全域性依賴,如bower,Dockerfile怎麼寫?

可以先安裝其他全域性依賴,再使用yarn安裝,記得命令寫在一個RUN指令裡, 下面是部分示例

RUN yarn config set registry https://registry.npm.taobao.org \
    && yarn global install bower \
    && bower i --allow-root \
    yarn複製程式碼

更多文章請看我的部落格

參考


相關文章