docker_postgresql.png

Dockerfile マルチステージビルド

最近Giteaソースコードを調べていたところ、プロジェクトのDockerfileの中に以下のコードスニペットを見つけました。

FROM golang:1.17-alpine3.15 AS build-env
#...
RUN go build contrib/environment-to-ini/environment-to-ini.go

FROM alpine:3.15
#...
COPY --from=build-env /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea
COPY --from=build-env /go/src/code.gitea.io/gitea/environment-to-ini /usr/local/bin/environment-to-ini

調べてみたところ、 dockerマルチステージビルドをサポートしていることがわかりました。マルチステージビルドとは、 Dockerfile内で中間イメージを構築できることを意味し、様々な既製の統合環境を容易に利用して、最終的な実行環境に必要なファイルをコンパイルできます。 最終的な環境は非常にクリーンなものとなり、コンパイル環境のインストールを必要とせず、最終的な実行に必要なファイルのみが含まれる。

古いDockerバージョンとCentOSシステムのメンテナンスが終了しました

Dockerfile修正し、Webサイトプロジェクトを再構築してフロントエンドとバックエンドを単一のコードリポジトリに統合した後、 Dockerバージョンが古いためにプロジェクトが正しくビルドされないという予期せぬ事態が発生しました。 さらに、現在のバージョンから最新のDockerバージョンにアップデートするには、古いバージョンをアンインストールしてから新しいバージョンをインストールする必要があります。私のウェブサイトのデータはすべてDockerボリュームに保存されているため、直接再インストールしても良い結果が得られる可能性は低いでしょう。ちょうどCentOS システムがメンテナンスを終了すると発表しました。メンテナンスが停止したシステムは必然的にバグが蓄積され、ソフトウェアサポートも低下します。そのため、 Ubuntuサーバーに切り替えることにしました。

ワイルドオペレーションおよびメンテナンスパス

サーバーの交換にはデータのバックアップと復旧が不可欠です。これは、USBドライブにデータをドラッグ&ドロップするだけでバックアップと復旧が完了する通常のシステムとは異なります。Docker Docker 、データはDockerボリュームに格納され、起動時に指定されたコンテナに動的にマウントされます。これらのボリュームからデータを削除し、再び格納する方法を知ることは、まさに熟練の技と言えるでしょう。 一般的なプロセスは、次の2つの部分に分けられます。まず、静的ファイルのパッケージ化と圧縮。

*backup.sh *

VOLUME_NAME=("volume1" "volume2" "volume3")
for VOLUME in "${VOLUME_NAME[@]}"
  do
    docker run --rm \
      # 创建数据卷,将项目的命名数据卷挂载到本中间容器上
      --volume "${VOLUME}:${TEMPORARY_DIRECTORY_TO_STORE_VOLUME_DATA}" \
      # 创建第二个数据卷,将主机上一个路径与容器内的备份数据所在目录进行映射
      --volume "${BACKUP_DATA_DIRECTORY}:${TEMPORARY_DIRECTORY_TO_STORE_BACKUP_FILE}" \
      # 用最小巧的alpine镜像来处理文件的压缩。
      alpine \
      # 容器内执行压缩命令
      tar cvf "${TEMPORARY_DIRECTORY_TO_STORE_BACKUP_FILE}/${VOLUME}.tar" ${TEMPORARY_DIRECTORY_TO_STORE_VOLUME_DATA}
      # 压缩完之后我们就可以在 BACKUP_DATA_DIRECTORY 里找到对应数据了
done

データベースファイルについては、直接コピーしないでください。代わりに、データベースに対応するバックアップおよび復元コマンドを使用してください。私はPostgreSQLを使用しています。

docker run -it --rm \
      # 在跑服务的时候最好自己设定网络名称,限制变化,这里将项目的网络与这个中间容器关联
      --network=${DOCKER_COMPOSE_PREFIX}_${NETWORK_NAME} \
      # 将项目的命名数据卷挂载到本中间容器
      --volume "${DOCKER_COMPOSE_PREFIX}_${DB_VOLUME_NAME}:${TEMPORARY_DIRECTORY_TO_STORE_VOLUME_DATA}" \
      # 可以在环境变量中指定数据库的密码
      --env PGPASSWORD="${PGPASSWORD}" \
      # 这里我直接使用与数据库相同的镜像,
      postgres:13.3-alpine \
      # pg_dump 命令输出数据库备份文件
      pg_dump \
      # 这里的host一般就是数据库容器名,因为与项目网络相连,所以才访问得到
      --host=${DB_HOST} \
      --username=${DB_USERNAME} \
      --dbname=${DB_NAME} \
      --format=p > "${BACKUP_DATA_DIRECTORY}/db_data/backup.sql"

ファイルのバックアップ後、 scpコマンドを使用してファイルを新しいサーバーに直接転送できます。

# 在旧服务器运行
scp -r /path/to/backup/file/directory username@new_server:/path/to/new/directory

それが不安な場合は、まずご自身のコンピューターにコピーしてください。

# 在本地运行
scp -r username@old_server:/path/to/backup/file/directory /path/to/my/computer/directory

もちろん、これらの2つのコマンドを実行するには、まずログインキーペアを設定する必要があります。

バックアップファイルの転送が完了したので、ようやく新しいサーバーにデータを復元できます。 新しいサーバー上にコンテナを構築した後、すぐにコンテナを起動しないでください。 コンテナが起動すると、特にデータベースにおいて、必然的に新しいデータが生成されます。起動後にコンテナを再開すると、競合が発生する可能性があります。

*restore.sh *

for VOLUME in "${VOLUME_NAME[@]}"
  do
    echo "${DOCKER_COMPOSE_PREFIX}_${VOLUME}"
    docker run --rm \
      --volume "${DOCKER_COMPOSE_PREFIX}_${VOLUME}:${TEMPORARY_DIRECTORY_TO_STORE_VOLUME_DATA}" \
      --volume "${BACKUP_DATA_DIRECTORY}:${TEMPORARY_DIRECTORY_TO_STORE_BACKUP_FILE}" \
      alpine \
      # 对应的解压命令
      tar xvf "${TEMPORARY_DIRECTORY_TO_STORE_BACKUP_FILE}/${VOLUME}.tar" -C ${TEMPORARY_DIRECTORY_TO_STORE_VOLUME_DATA} --strip 1
done

docker run -it --rm \
      --network=${DOCKER_COMPOSE_PREFIX}_${NETWORK_NAME} \
      --volume "${BACKUP_DATA_DIRECTORY}:${TEMPORARY_DIRECTORY_TO_STORE_BACKUP_FILE}" \
      --env PGPASSWORD="${PGPASSWORD}" \
      postgres:13.3-alpine \
      # 使用psql命令读取备份文件并恢复
      psql \
      --host=${DB_HOST} \
      --username=${DB_USERNAME} \
      --dbname=${DB_NAME} \
      --file="${TEMPORARY_DIRECTORY_TO_STORE_BACKUP_FILE}/db_data/backup.sql"

コンテナを再起動すると、以前のサーバーと全く同じように動作します!

プロセスを最適化し、人生を楽しもう

実際には、これらのスクリプトはファイルに保存され、直接実行することもできますし、 GNUMakeのMakefileを使用して特定の行ロジックを記述することもできます。 Makefileと疑問に思う人もいるかもしれません。 .shファイルの目的がクラスタ内でlinux shellコマンドを実行することであるならば、 Makefileはより高度なshellコマンド実行ファイルと言えるでしょう。 一連の長くて面倒なshellコマンドを、たった1、2語で実行できるファイルを作成できます。これでようやくコーヒーを一杯飲めますね。