專案小結:使用Docker遷移服務到離線伺服器

2023-06-09 18:00:23

前言

最近遇到的這個場景,需要把之前開發的一套系統遷移到一個離線的伺服器上,這個伺服器有點麻煩,接入VPN後通過堡壘機才能存取,速度也很慢,遇到不少坑,本文記錄一下遷移過程。

基本資訊

原本這套系統也挺簡單的,Django 寫的後端介面,搭配 Vue+Echarts 大屏,資料庫用 Mysql 和 Redis 作為快取,這些在原伺服器上都是用 docker 部署的。

這臺離線的伺服器是 Centos7.9 系統的,雖然不能存取外網,但還好有個原生的 yum 倉庫,可惜 yum 官方源少得可憐,只能安裝很有限的幾個軟體。

現在除了前端不需要遷移之外,其他的服務都需要遷移到這個離線的伺服器上。

遷移步驟:

  • 在離線伺服器上安裝 docker
  • 在原伺服器上匯出容器映象
  • 在離線伺服器上傳並匯入映象
  • 在離線伺服器上傳各種docker設定並啟動容器
  • 設定周邊元件,如 nginx

離線安裝docker

前面說到這個伺服器是有 yum 本地映象的,但裡面並沒有 docker,所以需要自行下載 docker 的 RPM 安裝包。

在這個地址: https://download.docker.com/linux/centos/7/x86_64/stable/Packages/

需要下載以下安裝包(版本號本文撰寫時的最新版,請讀者自行下載當下的最新版本)

  • containerd.io-1.6.21-3.1.el7.x86_64
  • docker-buildx-plugin-0.10.5-1.el7.x86_64
  • docker-ce-24.0.2-1.el7.x86_64
  • docker-ce-cli-24.0.2-1.el7.x86_64
  • docker-ce-rootless-extras-24.0.2-1.el7.x86_64
  • docker-compose-plugin-2.18.1-1.el7.x86_64

然後把這些安裝包都上傳到伺服器

執行命令安裝

sudo yum install containerd.io-1.6.21-3.1.el7.x86_64.rpm docker-ce-24.0.2-1.el7.x86_64.rpm # 以及其他...

就是把全部檔案都放在同一個 install 命令後面,因為這些包是有相互依賴要求的,如果一個個裝的話可能會因為順序問題報錯。

安裝之後啟動一下 docker

sudo systemctl enable docker
sudo systemctl start docker

新增使用者組啥的也屬於安裝 docker 後的常規操作了

sudo groupadd docker
sudo usermod -aG docker $USER
newgrp docker

之後就可以不使用 root 使用者來執行 docker 命令了

匯出映象

匯出映象有兩種方式

  • docker export - 對應 docker import 匯入映象
  • docker save - 對應 docker load 匯入映象

PS:這倆的匯出匯入命令的匹配的,不能混用

前者主要用於製作基礎映象,匯出後是沒有歷史記錄和後設資料的,也沒有 entrypoint 所以無法直接執行,這次遷移服務使用 save 方式。

操作命令

docker save <container_id> -o image.tar

也可以重定向

docker save <container_id> > image.tar

補充一下這倆方式的具體區別

  • 檔案大小不同,export 匯出的映象檔案體積小於 save 儲存的映象,因為 save 會把所有 layer 都匯出
  • save 可以把多個映象打包到一個檔案,export 不可以
  • export 匯出(import 匯入)是根據容器拿到的映象,再匯入時會丟失映象所有的歷史記錄和後設資料資訊(即僅儲存容器當時的快照狀態),所以無法進行回滾操作
  • save 儲存(load 載入)的映象,沒有丟失映象的歷史,可以回滾到之前的層(layer)

應用場景區別

  • docker export 的應用場景:主要用來製作基礎映象,比如我們從一個 ubuntu 映象啟動一個容器,然後安裝一些軟體和進行一些設定後,使用 docker export 儲存為一個基礎映象。然後,把這個映象分發給其他人使用,比如作為基礎的開發環境。
  • docker save 的應用場景:如果我們的應用是使用 docker-compose.yml 編排的多個映象組合,但我們要部署的客戶伺服器並不能連外網。這時就可以使用 docker save 將用到的映象打個包,然後拷貝到客戶伺服器上使用 docker load 載入。

打包資料

在舊的伺服器上,使用了 docker 來部署 MySQL 服務,並且將 data 對映出來,需要把 data 也一併遷移到新的伺服器上。

MySQL docker 的 volumes 設定

volumes:
	- ./data:/var/lib/mysql

因為VPN頻寬很低,這次使用 tar + bzip2 來打包壓縮

tar -cjvf ./data data.tar.bz2

命令引數說明:

  • -c: 建立一個壓縮檔案的引數指令 (create)
  • -j: 使用 bzip2 壓縮
  • -v: 壓縮的過程中顯示詳情 (verbose)
  • -f: 指定檔名,這個引數後面就不能再帶其他引數了

然後將這個 data.tar.bz2 上傳到新的伺服器。

解壓命令我也貼一下

tar -xjvf data.tar.bz2

這個命令會在當前目錄生成 data 目錄。

命令引數說明:

  • -x: 表示解壓 (extract)
  • 其他的引數上面有了

匯入映象

把前面匯出的 docker 映象上傳後,執行匯入命令

docker load < image.tar

之後執行 docker images 看看是否匯入成功

啟動容器

把原本的幾個 docker-compose 設定上傳

之前為了方便更新,Django專案是上傳程式碼之後在伺服器直接 build,像這樣

version: "3.6"
services:
  web:
    restart: always
    build: .
    environment:
      - ENVIRONMENT=docker
      - URL_PREFIX=demo/api
      - DEBUG=false
      - DEFAULT_DATABASE=mysql
    command: uwsgi uwsgi.ini
    volumes:
      - .:/code

但在離線伺服器上,沒有網路肯定是沒法 build 了

所以要把 build . 改成 image: 映象名稱

搞定後順利啟動~

設定周邊元件

只提供介面的話,也沒啥啦,再安裝個 nginx 就好

然而眾所周知 yum 的預設源連 nginx 都沒有,要安裝 nginx 的話還得新增 epel-release 源

sudo yum install epel-release

萬幸,離線伺服器的本地源有這個東西

sudo yum update
sudo yum install nginx

搞定~

然後還是老套路,用 systemctl 啟動 nginx,不重複了。

這個伺服器很折騰的,既然搞定了,得測試一下,但是介面都不開放,ssh連結也是通過多層跳轉的,好像沒法開啟 ssh-tunnel 轉發在本地測試。

所以只能用 curl 之類的工具來測試一下。

不過我這次另闢蹊徑,用命令列瀏覽器來試試能不能開啟專案的網頁。

分別試了這倆:

  • w3m
  • lynx

成功開啟了網頁,這倆瀏覽器的效果都差不多。

參考資料