GitLab CI/CDでSCP経由のデプロイを伴うComposerとnpmスクリプトの実行

このガイドでは、GitLab CI/CDを使ってnpmスクリプトでアセットをコンパイルしながら、PHPプロジェクトの依存関係を構築する方法を説明します。

PHPとNode.jsのバージョンをカスタマイズして独自のイメージを作成することも可能ですが、ここでは簡潔にするためにPHPとNode.jsがインストールされた既存のDockerイメージを使用します。

image: tetraweb/php

次のステップでは、zip/unzipパッケージをインストールし、Composerを利用できるようにします。これらをbefore_script セクションに配置します:

before_script:
  - apt-get update
  - apt-get install zip unzip
  - php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
  - php composer-setup.php
  - php -r "unlink('composer-setup.php');"

これですべての要件が揃いました。次に、composer install を実行してすべての PHP 依存パッケージを取得し、npm install を実行して Node.js パッケージを読み込みます。それからnpm スクリプトを実行します。before_script セクションに追加する必要があります:

before_script:
  # ...
  - php composer.phar install
  - npm install
  - npm run deploy

この場合、npm deploy スクリプトは Gulp スクリプトで、以下の処理を行います:

  1. CSSとJSのコンパイル
  2. スプライトの作成
  3. 様々なアセット(画像、フォント)のコピー
  4. 文字列の置換

これらのオペレーションにより、すべてのファイルがbuild フォルダに格納され、ライブサーバにデプロイする準備が整いました。

ライブサーバにファイルを転送する方法

rsync、SCP、SFTPなど複数の選択肢があります。今のところ、SCP を使用してください。

これを動作させるには、GitLab CI/CD 変数を追加する必要があります(gitlab.example/your-project-name/variables でアクセスできます)。この変数にSTAGING_PRIVATE_KEY という名前をつけ、サーバーの SSH秘密鍵を設定します。

セキュリティのヒント

更新が必要なフォルダのみにアクセスできるユーザーを作成します。

その変数を作成したら、実行時にそのキーがDockerコンテナに追加されていることを確認します:

before_script:
  # - ....
  - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
  - mkdir -p ~/.ssh
  - eval $(ssh-agent -s)
  - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'

順番に言うと、これは

  1. ssh-agent が利用可能かどうかをチェックし、利用可能でなければインストールします。
  2. ~/.ssh フォルダーを作成します。
  3. Bashを実行していることを確認します。
  4. ホストチェックを無効にします(最初にサーバーに接続するときにユーザーのacceptを求めません。すべてのジョブが最初の接続に等しいので、これが必要です)。

そして、before_script セクションで必要なのは基本的にこれだけです。

デプロイ方法

上で述べたように、Dockerイメージからbuild フォルダをサーバにデプロイする必要があります。そのために新しいジョブを作成します:

stage_deploy:
  artifacts:
    paths:
      - build/
  rules:
    - if: $CI_COMMIT_BRANCH == "dev"
  script:
    - ssh-add <(echo "$STAGING_PRIVATE_KEY")
    - ssh -p22 server_user@server_host "mkdir htdocs/wp-content/themes/_tmp"
    - scp -P22 -r build/* server_user@server_host:htdocs/wp-content/themes/_tmp
    - ssh -p22 server_user@server_host "mv htdocs/wp-content/themes/live htdocs/wp-content/themes/_old && mv htdocs/wp-content/themes/_tmp htdocs/wp-content/themes/live"
    - ssh -p22 server_user@server_host "rm -rf htdocs/wp-content/themes/_old"

以下はその内訳です:

  1. rules:if: $CI_COMMIT_BRANCH == "dev" このビルドは、dev ブランチに何かがプッシュされたときにのみ実行されます。このブロックを完全に削除して、すべてのビルドをプッシュされるたびに実行させることもできます(しかし、これはおそらくあなたが望まないことでしょう)。
  2. ssh-add ... ウェブUIで追加した秘密鍵をDockerコンテナに追加します。
  3. ssh 経由で接続し、新しい_tmp フォルダを作成します。
  4. scp 経由で接続し、build フォルダー(npm スクリプトによって生成されたもの)を、以前に作成した_tmp フォルダーにアップロードします。
  5. ssh 経由で再度接続し、live フォルダーを_old フォルダーに移動し、_tmpliveに移動します。
  6. SSHに接続し、_old フォルダーを削除します。

アーティファクトはどうするの?GitLab CI/CDにbuild ディレクトリを保持するように伝えます(後で、必要に応じてダウンロードできます)。

なぜこのようにするのか

ステージ・サーバーだけに使うのであれば、2つのステップでできます:

- ssh -p22 server_user@server_host "rm -rf htdocs/wp-content/themes/live/*"
- scp -P22 -r build/* server_user@server_host:htdocs/wp-content/themes/live

問題は、サーバーにアプリがない期間が少しあることです。

そのため、本番環境では、いつでも機能的なアプリが配置されていることを保証するために、追加のステップを使用します。

次のステップ

これはWordPressのプロジェクトなので、実際のコードスニペットも含まれています。さらに追求できるアイデアもあります:

  • デフォルトのブランチとは少し異なるスクリプトを用意することで、そのブランチから本番サーバーにデプロイしたり、他のブランチからステージサーバーにデプロイしたりできるようになります。
  • ライブでプッシュする代わりに、WordPress の公式リポジトリにプッシュすることもできます。
  • その場で国際化テキストドメインを生成できます。

最終的な.gitlab-ci.yml はこのようになります:

stage_deploy:
  image: tetraweb/php
  artifacts:
    paths:
      - build/
  rules:
    - if: $CI_COMMIT_BRANCH == "dev"
  before_script:
    - apt-get update
    - apt-get install zip unzip
    - php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
    - php composer-setup.php
    - php -r "unlink('composer-setup.php');"
    - php composer.phar install
    - npm install
    - npm run deploy
    - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
    - mkdir -p ~/.ssh
    - eval $(ssh-agent -s)
    - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'
  script:
    - ssh-add <(echo "$STAGING_PRIVATE_KEY")
    - ssh -p22 server_user@server_host "mkdir htdocs/wp-content/themes/_tmp"
    - scp -P22 -r build/* server_user@server_host:htdocs/wp-content/themes/_tmp
    - ssh -p22 server_user@server_host "mv htdocs/wp-content/themes/live htdocs/wp-content/themes/_old && mv htdocs/wp-content/themes/_tmp htdocs/wp-content/themes/live"
    - ssh -p22 server_user@server_host "rm -rf htdocs/wp-content/themes/_old"