聊聊如何通過docker-compose將node服務部署到多套環境中

2022-01-28 19:00:07
如何通過docker-compose將服務部署到多套環境?下面本篇文章就來給大家介紹一下Docker-compose多環境部署Node服務的方法,希望對大家有所幫助!

一般情況下,我們專案在開發完成之後,需要部署到多套環境,比如測試、沙箱、整合等等,那麼如何通過docker-compose將node服務部署到多套環境呢?下面文章具體說下,有什麼不對的地方歡迎大家評論。

本文中的專案用到的技術是Gitlab+Ansible+Docker自動化部署node服務(nest框架寫的),步驟如下:

  • 編寫docker-compose、docker-compose.prod.yml組態檔

  • 修改package.json

  • 遠端伺服器上建立兩個目錄,拉取node服務倉庫,切換到不同分支,分別表示測試、線上node服務

  • .gitlab-ci.yml檔案編寫

  • ansible.yml檔案編寫

  • 遠端伺服器node服務(測試/線上)目錄下執行如下命令,執行之後,通過docker ps -a檢視容器是否正常啟動,如果是up狀態掛起,證明容器啟動成功了。docker logs -f 容器id檢視容器紀錄檔

# 測試目錄 /opt/xxx/server-test/server
docker-compose up -d

# 線上目錄 /opt/xxx/server-prod/server
# -f表示指定具體檔案,預設執行的是docker-compose.yml檔案
docker-compose -f docker-compose.prod.yml up -d

具體步驟

  • 編寫docker-compose、docker-compose.prod.yml組態檔

# docker-compose.yml
version: '3.0'
services: # 服務列表
  # 測試資料庫
  mysql:
    image: mysql
    container_name: mysql_test
    restart: always
    environment:
      - MYSQL_ROOT_PASSWORD=test_sql
      - NODE_ENV=development
    ports:
      - 13306:3306
    volumes:
      - 伺服器上對應目錄:/var/lib/mysql
      
  # 測試node服務
  server:  # node服務
    container_name: server-test # 容器名稱
    image: node:14.15.0
    ports:  # 暴露的埠
      - "7007:5088"
    environment: 
      - NODE_ENV=development
    volumes:
      - .:/data
    working_dir: /data
    depends_on: # web服務依靠mysql要先等mysql啟動
      - mysql
    restart: on-failure:5 # 自動重新啟動,失敗的話重新啟動5次後停止
    command: yarn start # 覆蓋容器啟動後預設執行的命令
# docker-compose.prod.yml
version: '3.0'
services: # 服務列表
  # 線上資料庫
  prod-mysql:
    image: mysql
    container_name: mysql_prod
    restart: always
    environment:
      - MYSQL_ROOT_PASSWORD=prod_sql
      - NODE_ENV=production
    ports:
      - 13307:3306
    volumes:
      - 伺服器上對應目錄:/var/lib/mysql

  # 線上node服務
  prod-server:
    container_name: server-prod
    image: node:14.15.0
    ports:
      - "7077:5089"
    environment: 
      - NODE_ENV=production
    volumes:
      - .:/data
    working_dir: /data
    depends_on:
      - prod-mysql
    restart: on-failure:5
    command: yarn start:prod
  • package.json中做如下修改

# cross-env指定NODE_ENV為開發或線上環境
...
"scripts": {
    ...
    "build": "nest build",
    "start": "yarn && cross-env  NODE_ENV=development nest start",
    "start:prod": "yarn && yarn build && cross-env  NODE_ENV=production node dist/src/main",
    ...
  },
...
  • 遠端伺服器上建立兩個目錄,分別存放測試、線上node服務

# 測試(dev分支),git clone node服務地址,切換到dev分支
/opt/xxx/server-test/server

# 線上(master分支),git clone node服務地址,切換到master分支
/opt/xxx/server-prod/server
  • .gitlab-ci.yml檔案編寫

# CI變數說明說明
- BRANCH、DEV_BRANCH是CI變數,分別對應master、dev分支
- DOCKER_CONTAINER、DEV_DOCKER_CONTAINER分別對應線上、測試啟動的docker容器
- ROOT_PATH、DEV_ROOT_PATH分別對應遠端伺服器上線上、測試node服務存放路徑
- CI_PROJECT_NAME表示gitlab上倉庫名稱

stages:
  - dev_deploy
  - master_deploy

master_deploy:
  stage: master_deploy
  image: ansible映象地址
  script:
    - echo \"${HOST}\" ansible_ssh_user=\"${USER}\" ansible_ssh_pass=\"${PASS}\" ansible_ssh_host=\"${HOST}\" > hosts
    - echo ansible-playbook ansible.yaml -e hosts=${HOST} -i ./hosts
    - ansible-playbook ansible.yaml -e "HOST=${HOST}  DEST_PATH=${ROOT_PATH}/${CI_PROJECT_NAME} DOCKER_CONTAINER_NAME=${DOCKER_CONTAINER} CUR_BRANCH=${BRANCH}" -i ./hosts
    - rm -f hosts
  only:
    - master
  tags:
    - k8s

dev_deploy:
  stage: dev_deploy
  image: ansible映象地址
  script:
    - echo \"${HOST}\" ansible_ssh_user=\"${USER}\" ansible_ssh_pass=\"${PASS}\" ansible_ssh_host=\"${HOST}\" > hosts
    - echo ansible-playbook ansible.yaml -e hosts=${HOST} -i ./hosts
    - ansible-playbook ansible.yaml -e "HOST=${HOST}  DEST_PATH=${DEV_ROOT_PATH}/${CI_PROJECT_NAME} DOCKER_CONTAINER_NAME=${DEV_DOCKER_CONTAINER} CUR_BRANCH=${DEV_BRANCH}" -i ./hosts
    - rm -f hosts
  only:
    - dev
  tags:
    - k8s
  • ansible.yml檔案編寫

# cd到node服務server目錄,切換分支,拉取最新程式碼,docker容器重新啟動
- name: deploy
  hosts: "{{ HOST }}"
  become_user: root
  become: yes
  tasks: # 任務
    - name: git checkout branch
      command: git checkout "{{CUR_BRANCH}}"
      args:
        chdir: "{{ DEST_PATH }}"
    - name: git pull
      command: git pull
      args:
        chdir: "{{ DEST_PATH }}"
    - name: docker restart container
      command: docker restart "{{ DOCKER_CONTAINER_NAME }}"
      args:
        chdir: "{{ DEST_PATH }}"
  • 遠端伺服器node服務(測試/線上)目錄下執行如下命令

# 測試目錄 /opt/xxx/server-test/server
docker-compose up -d

# 線上目錄 /opt/xxx/server-prod/server
docker-compose -f docker-compose.prod.yml up -d

啟動成功之後通過docker ps -a檢視容器啟動情況,具體如下圖所示:

1.png

說明

  • 測試環境:本地dev分支程式碼提交或其他分支合併到dev分支時,會通過itlab CI、Ansible自動化部署node服務到遠端伺服器,在對應伺服器遠端目錄下切換分支、拉取最新程式碼、重新啟動對應的測試docker容器

  • 線上環境:本地master分支程式碼提交或其他分支合併到master分支時,會通過itlab CI、Ansible自動化部署node服務到遠端伺服器,在對應伺服器遠端目錄下切換分支、拉取最新程式碼、重新啟動對應的線上docker容器

遇到的問題

問題一:測試/線上遠端node服務目錄下沒有node_modules目錄和dist目錄,即沒有下圖這兩個檔案同時遠端伺服器器上檢視docker容器紀錄檔報如下錯誤(這個問題排查了好久才解決

2.png

3.png

排查: 發現和正常啟動的node服務容器對比來看,沒有這兩個目錄(dist和node_modules),排查是不是docker-compose.yml中command執行命令有問題,即docker-compose.yml的command中yarn && yarn start是不是有問題,於是嘗試把yarn操作放在package.json中,結果好啦。

解決:

# 修改前
# docker-compose.yml
version: '3.0'
services:
  ...
  server:
    ...
    command: yarn && yarn start
    
# package.json
"scripts": {
    ...
    "build": "nest build",
    "start": "cross-env  NODE_ENV=development nest start",
    "start:prod": "cross-env  NODE_ENV=production yarn build && node dist/src/main",
    ...
  },
    
# 修改後
# docker-compose.yml
version: '3.0'
services:
  ...
  server:
    ...
    command: yarn start
    
# package.json
方案一:
"scripts": {
    ...
    "build": "nest build",
    "start": "yarn && cross-env  NODE_ENV=development nest start",
    "start:prod": "yarn && yarn build && cross-env  NODE_ENV=production node dist/src/main",
    ...
  },
  
方案二:
"scripts": {
    ...
    "build": "nest build",
    "start": "cross-env NODE_ENV=development nest start",
    "prestart": "yarn",
    "start:prod": "yarn build && cross-env  NODE_ENV=production node dist/src/main",
    "prestart:prod": "yarn",
    ...
},

注意

  • cross-env的位置,放在可執行命令之前,在本專案中,放在最前面伺服器上報cross-env not found, 放在最後面環境變數不生效,NODE_ENV顯示undefined

  • script中可執行命令注意執行順序,比如yarn && yarn build && cross-env NODE_ENV=production node dist/src/main

  • script中pre

問題2: 前端線上域名對映不生效,nginx組態檔對映線上域名之後,發現存取線上域名時,發現頁面沒有生效

排查:將nginx測試組態檔和線上組態檔對比,發現檔案內容除了域名和api代理,其餘都是一樣,那到底是什麼原因呢?最後發現竟然是線上nginx組態檔字尾名不對,寫的是xxx.confg,此處心裡一萬個想打死自己

解決: 修改線上nginx組態檔為正確的字尾,即xxx.conf字尾

問題三:Gitlab CI執行異常,具體報錯資訊大概是報/server目錄找不到

排查:在CI裡面列印輸出CI變數以及拼接出來的目錄變數,檢視是哪一步有問題,經排查發現都是正常的,唯一不同的一點是CI變數後面設定了環境變數

解決:嘗試把環境變數改為All default,結果好了,記住,不要隨意設定CI後面的環境變數,如果修改的話,對應的Gitlab裡面也是對應需要對映的,環境變數位置如下圖所示:

4.png

master_deploy:
  ...
  script:
    ...
    - echo ${ROOT_PATH}
    - echo ${CI_PROJECT_NAME}
    - echo ${ROOT_PATH}/${CI_PROJECT_NAME}
    - echo ${DOCKER_CONTAINER}
    - echo ${BRANCH}
    ...
 ...

本文到這就結束了,後面還會有一篇檔案,講全棧專案從開發到自動化部署整個過程(用到的技術棧是Vue + Nest + Typeorm + Mysql+ Gitlab CI + Ansible + Docker)。

推薦學習:《》、《》

以上就是聊聊如何通過docker-compose將node服務部署到多套環境中的詳細內容,更多請關注TW511.COM其它相關文章!