レビューアプリ
レビューアプリはパイプラインによって自動的にデプロイされます。
どのように機能するのですか?
CI/CDアーキテクチャ図
(canonical default refs only)"]; B[review-build-cng]; C[review-deploy]; D[CNG-mirror]; E[review-qa-smoke]; A -->|once the `prepare` stage is done| B B -.->|triggers a CNG-mirror pipeline and wait for it to be done| D D -.->|polls until completed| B B -->|once the `review-build-cng` job is done| C C -->|once the `review-deploy` job is done| E subgraph "1. gitlab `prepare` stage" A end subgraph "2. gitlab `review-prepare` stage" B end subgraph "3. gitlab `review` stage" C["review-deploy
Helm deploys the Review App using the Cloud
Native images built by the CNG-mirror pipeline.
Cloud Native images are deployed to the `review-apps`
Kubernetes (GKE) cluster, in the GCP `gitlab-review-apps` project."] end subgraph "4. gitlab `qa` stage" E[review-qa-smoke
gitlab-qa runs the smoke suite against the Review App.] end subgraph "CNG-mirror pipeline" D>Cloud Native images are built]; end
詳細説明
-
test
ステージでは、パイプラインごとにgitlab:assets:compile
のジョブが自動的に開始されます。- それが完了すると、次のステップでトリガーされる
CNG-mirror
パイプラインがそれに依存するため、review-build-cng
手動ジョブを開始します。
- それが完了すると、次のステップでトリガーされる
-
review-build-cng
ジョブはCNG-mirror
プロジェクトのパイプラインをトリガーします。-
CNG-mirror
パイプラインは、GitLab パイプラインからのコミットに基づいて、各コンポーネントの Docker イメージ (gitlab-rails-ee
,gitlab-shell
,gitaly
など) を作成し、レジストリに保存します。 -
CNG
, (Cloud Native GitLab)プロジェクトのレジストリに多くの一時的なDockerイメージが過負荷にならないように、CNG-mirror
プロジェクトを使用しています。 - 公式CNG画像は、
cloud-native-image
ジョブによってビルドされます。このジョブはタグのためだけに実行され、CNG
パイプラインをトリガーします。
-
-
test
ステージが完了したら、review-deploy
ジョブは公式 GitLab Helm チャートを使ってレビューアプリを GCP 上のreview-apps
Kubernetes クラスタにデプロイします。- レビューアプリのデプロイに使用される実際のスクリプトは、
scripts/review_apps/review-apps.sh
にあります。 - これらのスクリプトは基本的に公式のAuto DevOpsスクリプトで、デフォルトのCNGイメージはビルドされたイメージで上書きされ、
CNG-mirror
プロジェクトのレジストリに保存されます。 - 公式のGitLab Helmチャートを使っているので、本番環境に近いブランチ専用の環境を手に入れることができます。
- レビューアプリのデプロイに使用される実際のスクリプトは、
-
review-deploy
ジョブが成功すると、MR ウィジェットからレビューアプリに直接リンクされるため、レビューアプリを使用できるようになります。 レビューアプリにログインするには、以下の「レビューアプリにログインしますか?
追記
-
review-deploy
ジョブが失敗し続ける場合 (すでに 2 回再試行していることに注意してください)、#g_qe_engineering_productivity
チャンネルにメッセージを投稿するか、マージリクエストへのリンクを含む~"Engineering Productivity"
~"ep::review apps"
~bug
イシューを作成してください。 デプロイの失敗によって、マージリクエストで導入された実際の問題が明らかになる可能性があることに注意してください (つまり、これは必ずしも一過性の失敗ではありません)! -
review-qa-smoke
のジョブが失敗し続ける場合 (すでに2回リトライしていることに注意してください)、ジョブのログをチェックしてください: あなたのマージリクエストで導入された実際の問題を発見できるかもしれません。 また、失敗が発生したときのページのスクリーンショットを見るためにアーティファクトをダウンロードすることもできます。 失敗の原因が見つからない場合、もしくはあなたの変更とは無関係と思われる場合、#quality
チャンネルにメッセージを投稿するか、もしくはあなたのマージリクエストへのリンクを含む ~Quality ~bug issue を作成してください。 - 手動
review-stop
はレビューアプリを手動で停止させるのに使えます。また、マージリクエストのブランチがマージ後に削除されると、GitLab によって開始されます。 - Kubernetesクラスタは、GitLabのKubernetesインテグレーションを使って
gitlab-{ce,ee}
プロジェクトに接続されています。 これにより、基本的にマージリクエストウィジェットから直接レビューアプリにリンクすることができます。
レビューアプリの自動停止
レビューアプリは、環境自動停止機能により、最後のデプロイから2日後に自動的に停止します。
レビューアプリをより長い時間立ち上げておく必要がある場合は、その環境を固定するか、review-deploy
ジョブを再試行して「最新のデプロイ時」に更新することができます。
スケジュールされたパイプラインで自動的に実行されるreview-cleanup
ジョブ (マージリクエストでは手動) は、5日後に古いレビューアプリを停止し、6日後にその環境を削除し、7日後にぶら下がっている Helm リリースと Kubernetes リソースをクリーンアップします。
スケジュールされたパイプラインで自動的に実行される(マージリクエストでは手動で実行される)review-gcp-cleanup
ジョブは、Kubernetes リソースと一緒に削除されなかったぶら下がっている GCP ネットワークリソースを削除します。
QAラン
qa
ステージ (review
ステージの後) のすべてのパイプラインで、review-qa-smoke
ジョブが自動的に開始され、QA スモークスイートが実行されます。
手動でreview-qa-all
を起動することもできます:完全なQAスイートを実行します。
パフォーマンス・メトリクス
qa
ステージのすべてのパイプラインで、review-performance
ジョブが自動的に開始されます。このジョブは、Sitespeed.ioコンテナを使用して基本的なブラウザのパフォーマンステストを行います。
クラスター構成
ノードプール
review-apps
クラスターは現在、以下のノードプールでセットアップされています:
-
e2-highcpu-16
(16vCPU、16GBメモリ)プリエンプティブノード、オートスケーリング機能付き
Helm
使用される Helm のバージョンは、review-deploy
とreview-stop
のジョブで使用されるregistry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-helm3-kubectl1.14
イメージで定義されています。
どのように
GCPレビューアプリクラスターへのアクセス
gcp-review-apps-sg
GCPグループへのアクセスリクエスト(内部リンク)を開く必要があります。 グループに参加するには、アクセスリクエストで希望するGCPロールを指定する必要があります。 ロールは、レビューアプリコンテナに参加するための特定の権限を付与するものです。
以下は、あなたが持ちたいと思う権限と、それを与えるロールです:
-
container.pods.getLogs
-ポッドログを取得するために必要です。Viewer (roles/viewer
)によって許可されます。 -
container.pods.exec
-Rails コンソールを実行するために必要です。Kubernetes Engine Developer (roles/container.developer
)によって付与されます。
レビューアプリへのログイン
デフォルトのユーザー名はroot
で、パスワードは 1Password セキュアノートgitlab-{ce,ee} Review App's root password
に記載されています。
レビューアプリの機能フラグを有効にします。
- レビューアプリを開き、上記の手順でログインします。
- 個人アクセストークンを作成します。
- 機能フラグAPIを使用して機能フラグを有効にします。
レビューアプリのスラッグを探す
-
review-deploy
ジョブを開きます。 -
Checking for previous deployment of review-*
を探してください。 - 例えば
Checking for previous deployment of review-qa-raise-e-12chm0
の場合、レビューアプリのスラッグはreview-qa-raise-e-12chm0
となります。
Railsコンソールの実行
- まずクラスターへのアクセス権限と
container.pods.exec
権限があることを確認してください。 -
レビューアプリのスラッグ(例:
review-qa-raise-e-12chm0
)でワークロードをフィルタリングします。 -
review-qa-raise-e-12chm0-task-runner
など、task-runner
デプロイを見つけて開いてください。 - 管理対象ポッド」セクションのポッドをクリックします(例:
review-qa-raise-e-12chm0-task-runner-d5455cc8-2lsvz
)。 -
KUBECTL
ドロップダウンをクリックし、Exec
->task-runner
。 -
-c task-runner -- ls
をデフォルトコマンドの-it -- gitlab-rails console
に置き換えるか、または-
kubectl exec --namespace review-apps review-qa-raise-e-12chm0-task-runner-d5455cc8-2lsvz -it -- gitlab-rails console
を実行してください。-
review-qa-raise-e-12chm0-task-runner-d5455cc8-2lsvz
をポッドの名前に置き換えてください。
-
-
ポッドの過去ログを探る
- まずクラスターへのアクセス権限と
container.pods.getLogs
権限があることを確認してください。 -
レビューアプリのスラッグ(例:
review-qa-raise-e-12chm0
)でワークロードをフィルタリングします。 -
review-qa-raise-e-12chm0-migrations.1
など、migrations
デプロイを見つけて開いてください。 - 管理対象ポッド」セクションのポッドをクリックします(例:
review-qa-raise-e-12chm0-migrations.1-nqwtx
)。 -
Container logs
リンクをクリックしてください。
不健康なレビューアプリのリリース診断
レビューアプリの安定性が低下した場合は、review-apps-ce/ee
クラスターが不健全であることを示すシグナルである可能性があります。先行指標としては、再起動につながるヘルスチェックの失敗や、レビューアプリのデプロイの大半の失敗が考えられます。
レビューアプリの概要ダッシュボードは、クラスターの負荷スパイクを特定し、ノードに問題がある場合やクラスター全体が不健全な傾向にある場合に役立ちます。
でリリースに失敗しました。ImagePullBackOff
考えられる原因
ImagePullBackoff
ステータスが表示された場合は、Docker イメージが不足していないか確認してください。
さらなるデバッグのための場所
Dockerイメージが作成されたことを確認するには、以下のDockerコマンドを実行します:
`DOCKER_CLI_EXPERIMENTAL=enabled docker manifest repository:tag`
このコマンドの出力は、Dockerイメージが存在するかどうかを示します。 例えば、以下のようになります:
DOCKER_CLI_EXPERIMENTAL=enabled docker manifest inspect registry.gitlab.com/gitlab-org/build/cng-mirror/gitlab-rails-ee:39467-allow-a-release-s-associated-milestones-to-be-edited-thro
Dockerイメージが存在しない場合:
-
helm upgrade --install
コマンドのimage.repository
とimage.tag
オプションが、CNG-mirror パイプラインで使用されるリポジトリ名と一致していることを確認します。 -
review-build-cng
ジョブの対応する下流のCNG-ミラーパイプラインをさらに見てください。
ノード数は常に増加(つまり、安定することも減少することもない)
考えられる原因
これはreview-cleanup
ジョブが古いレビューアプリと Kubernetes リソースのクリーンアップに失敗しているサインかもしれません。
さらなるデバッグのための場所
最新のreview-cleanup
ジョブログを見て、予期せぬ障害が発生していないか確認してください。
p99のCPU使用率は、ほとんどのノードおよび/または多くのコンポーネントで100%です。
考えられる原因
これは、Helmがレビューアプリのデプロイに失敗している兆候かもしれません。HelmにFAILED
リリースが多い場合、CPU使用率が増加しているようですが、これはおそらくHelmまたはKubernetesがコンポーネントを再作成しようとしているためです。
さらなるデバッグのための場所
最近のreview-deploy
のジョブ・ログを見てください。
便利なコマンド
# Identify if node spikes are common or load on specific nodes which may get rebalanced by the Kubernetes scheduler
kubectl top nodes | sort --key 3 --numeric
# Identify pods under heavy CPU load
kubectl top pods | sort --key 2 --numeric
logging/user/events/FailedMount
チャートが上昇しています。
考えられる原因
これは、古いシークレットやコンフィギュレーションマップが多すぎるサインかもしれません。
さらなるデバッグのための場所
コンフィギュレーションまたはkubectl get secret,cm --sort-by='{.metadata.creationTimestamp}' | grep 'review-'
のリストを見てください。
5日以上前のシークレットや構成マップは疑わしいので削除してください。
便利なコマンド
# List secrets and config maps ordered by created date
kubectl get secret,cm --sort-by='{.metadata.creationTimestamp}' | grep 'review-'
# Delete all secrets that are 5 to 9 days old
kubectl get secret --sort-by='{.metadata.creationTimestamp}' | grep '^review-' | grep '[5-9]d$' | cut -d' ' -f1 | xargs kubectl delete secret
# Delete all secrets that are 10 to 99 days old
kubectl get secret --sort-by='{.metadata.creationTimestamp}' | grep '^review-' | grep '[1-9][0-9]d$' | cut -d' ' -f1 | xargs kubectl delete secret
# Delete all config maps that are 5 to 9 days old
kubectl get cm --sort-by='{.metadata.creationTimestamp}' | grep 'review-' | grep -v 'dns-gitlab-review-app' | grep '[5-9]d$' | cut -d' ' -f1 | xargs kubectl delete cm
# Delete all config maps that are 10 to 99 days old
kubectl get cm --sort-by='{.metadata.creationTimestamp}' | grep 'review-' | grep -v 'dns-gitlab-review-app' | grep '[1-9][0-9]d$' | cut -d' ' -f1 | xargs kubectl delete cm
K9の使用
K9sは、ラベルでフィルタリングできる強力なコマンドラインダッシュボードです。 これは、レビューアプリのリソース要求を超えるアプリの傾向を特定するのに役立ちます。 Kubernetesは、リソース要求に基づいてポッドをノードにスケジューリングし、上限までのCPU使用を許可します。
- K9sでは、
/
文字を入力することで、並べ替えやフィルタの追加ができます。-
-lrelease=<review-app-slug>
- これは、1つのデプロイで何が問題になっているかを判断するのに役立ちます。 -
-lapp=<app>
- これは、アプリごとのリソース使用量を判断するのに役立ちます。
-
- Kubernetesリソースまでスクロールし、
d
(describe)、s
(shell)、l
(logs)をクリックすると、より深く調べることができます。
保留中のdns-gitlab-review-app-external-dns
デプロイのトラブルシューティング
問題の発見
過去に、dns-gitlab-review-app-external-dns
デプロイが保留状態になり、すべてのレビューアプリに DNS レコードが割り当てられず、ドメイン名でアクセスできなくなることがありました。
その結果、レビューアプリの他のコンポーネントが正しく起動しなくなりました(例:gitlab-runner
)。
いくつかの調査の結果、systemd-mount
のトランジェント・スコープ(ポッドなど)を使用した場合、新しいマウントが失敗することがわかりました:
MountVolume.SetUp failed for volume "dns-gitlab-review-app-external-dns-token-sj5jm" : mount failed: exit status 1
Mounting command: systemd-run
Mounting arguments: --description=Kubernetes transient mount for /var/lib/kubelet/pods/06add1c3-87b4-11e9-80a9-42010a800107/volumes/kubernetes.io~secret/dns-gitlab-review-app-external-dns-token-sj5jm --scope -- mount -t tmpfs tmpfs /var/lib/kubelet/pods/06add1c3-87b4-11e9-80a9-42010a800107/volumes/kubernetes.io~secret/dns-gitlab-review-app-external-dns-token-sj5jm
Output: Failed to start transient scope unit: Connection timed out
これはおそらく、GitLabのChartが67個のリソースを作成し、基盤となるGCPノードに多くのマウントポイントが作成されたために起こったと思われます。
根本的なイシューは、systemd
のバグで、systemd
v237
で修正されたようです。 残念ながら、私たちのGCPノードは現在、v232
を使用しています。
ちなみに、このイシューを発見するためのデバッグ手順は以下の通り:
- kubectlのコンテキストをreview-apps-ceに切り替えます(kubectxの使用をお勧めします)
kubectl get pods | grep dns
-
kubectl describe pod <pod name>
正確なエラーメッセージの確認 - 正確なエラーメッセージをウェブ検索し、関連するKubernetesバグレポートへのラビットホールをたどります。
- GCPコンソールからSSH経由でノードにアクセスします(Computer Engine > VMインスタンスの順にクリックし、
dns-gitlab-review-app-external-dns
ポッドが実行されているノードの「SSH」ボタンをクリックします)。 - ノード内部:
systemctl --version
=>systemd 232
- もっと情報を集めてください:
-
mount | grep kube | wc -l
=> 例:290 -
systemctl list-units --all | grep -i var-lib-kube | wc -l
=> 例:142
-
- 悪い状態のポッドがいくつあるか確認してください:
- 指定したノードで動作しているすべてのポッドを取得します:
kubectl get pods --field-selector=spec.nodeName=NODE_NAME
- 指定したノード上の
Running
ポッドをすべて取得します:kubectl get pods --field-selector=spec.nodeName=NODE_NAME | grep Running
- 指定されたノードのバッド状態のポッドをすべて取得します:
kubectl get pods --field-selector=spec.nodeName=NODE_NAME | grep -v 'Running' | grep -v 'Completed'
- 指定したノードで動作しているすべてのポッドを取得します:
問題の解決
この問題を解決するためには、いくつかのノードから(強制的に)水を抜く必要がありました:
- Kubernetes が自動的に別のノードに移動するように、
dns-gitlab-review-app-external-dns
ポッドが実行されているノードで通常のドレインを試してください:kubectl drain NODE_NAME
- それでもうまくいかない場合は、すべてのポッドを削除してノードを強制的に「ドレイン」することもできます:
kubectl delete pods --field-selector=spec.nodeName=NODE_NAME
- ノードの中で:
-
systemctl daemon-reload
を実行し、死活ユニット/不活性ユニットを取り除きます。 - それでも問題が解決しない場合は、ハード再起動を行ってください:
sudo systemctl reboot
-
- コード化されたノードのコードを解除します:
kubectl uncordon NODE_NAME
並行して、ほとんどのレビューアプリが壊れた状態にあったため、それらを削除してRunning
以外のポッドのリストを整理しました。以下は、最終デプロイ日(現在の日付は当時6月6日)に基づいてレビューアプリを削除するコマンドです。
helm ls -d | grep "Jun 4" | cut -f1 | xargs helm delete --purge
将来この問題を回避するために講じられた緩和策
今後、マシンが “マウントポイントが多すぎる “問題にぶつかる可能性が低くなるように、小さいマシンで新しいノードプールを作りました。
よくある質問
テスト実行のたびにCNGイメージのビルドをトリガーするのはやりすぎではありませんか? これでは何千もの未使用のDockerイメージができてしまいます。
また、CNG-mirrorプロジェクトを使ってDockerイメージを保存しているので、ある時点でレジストリを消去して、新しく空のものを使うことができます。
アプリは世界中に公開されているので、私たちだけに限定する方法を見つける必要があります。
これはフォークでは有効ではありません。