虎の穴開発室ブログ

虎の穴ラボ株式会社所属のエンジニアが書く技術ブログです

MENU

Atlantis + Cloudflare TunnelでTerraformの自動実行環境を導入する

こんにちは、虎の穴ラボ インフラエンジニアのかなざわです。

本記事は虎の穴ラボAdvent Calendar 2022-Qiitaの13日目の記事です。

12日目はgodanさんによる「Google Apps Scriptでダンジョンゲームを作る」が投稿されました。

14日目は虎の穴ラボ デザインチームによる「デザインチームが自ら企画&開発に挑戦?!クリエイター向け新サービス「デジタルサインカード」をつくってみた」が投稿されます。こちらもぜひご覧ください。

はじめに

私は新しい機能の確認や検証の場所として、プライベートでAWSアカウントを契約し利用しています。AWSに構築した各種リソースはTerraformとVCS(GitHub)でコード管理を行っています。そして、インフラリソースを構築する時は自分の端末からterraformコマンドを実施していました。

その方法でもリソースの作成に支障は無いですが、「terraformコマンドを実施する」という手動オペレーションが存在している部分を改善したいと考えており、今回AtlantisというVCSと連携するTerraformの自動実行環境を導入しました。

Atlantisは、いわゆるSaaSのようなサービスではなくOSSのため、どこかにホスティングを行い運用する必要があります。EC2やECS、また外部のVPSにホスティングするのも手ですがこの自動実行にできるだけお金をかけたくなかったのもあり、今回は自宅にあるローカルKubernetesへのデプロイを検討しました。

また、Atlantisは各種VCSからのWebhookを受信できることが必要になるため、基本的には外部から接続できる必要があります。そのため、今回はローカルKubernetesにへデプロイしたAtlantisをCloudflare Tunnelを使用し外部公開することで、VCSと連携できるようにしました。

今回はこの構築した内容について紹介します。

Atlantis とは

AtlantisはTerraformの自動実行環境を提供するOSSです。

GitHubやGitLabなどのVCSと連携し、VCSへのプルリクエストやコメントを行うことでterraformコマンドを実施します。terraform planの結果はプルリクエストのスレッド上に表示され、目視で確認することができます。

前述の通りホスティングの手間はありますが、上記の自動実行はもちろん、プルリクエストのスレッド上でこのような操作を行うため「いつ誰が何をやった」という証跡を確認しやすい点が魅力的に映りました。

Cloudflare Tunnel とは

Cloudflare Tunnelは、Cloudflare社が提供するゼロトラストセキュリティソリューションの一機能です。インフラ内部にcloudflaredというデーモンを配置し、Cloudflareが所有するエッジとの間にアウトバウンド接続用のTunnelを作成します。これにより、インフラの外側からCloudflareのエッジを経由しインフラ内部のリソースにアクセスすることができます。

https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/

アクセスURLをカスタムドメインとすることもできます。カスタムドメインの管理費はかかりますが、Cloudflare Tunnelを使用することは無料で可能です。なお今回はURLが固定されていたほうが都合がよかったことからカスタムドメインを使用する方針としました。

シンプルな構成の構築

まずはシンプルな構成を確認してみます。

  • GitHub
    • GitHubユーザでPersonal Access Tokenを作成
    • GitHubリポジトリでWebhookを作成

Atlantis の公式ドキュメントにあるGit Host Access Credentialsに従い、Credentialsを払い出します。

Cloudflare TunnelおよびAtlantisは、それぞれバイナリをダウンロードし実行します。

  • Cloudflare Tunnel の実行
## Cloudflaredのダウンロード
$ CLOUDFLARED_VERSION=2022.11.1
$ wget -O cloudflared https://github.com/cloudflare/cloudflared/releases/download/$CLOUDFLARED_VERSION/cloudflared-linux-amd64
$ chmod a+x cloudflared
## Cloudflaredの実行
$ ./cloudflared tuunel --url localhost:4141

実行すると自動生成および表示されるtrycloudflare.comドメインのURLをメモします。

  • Atlantis の実行
## Atlantisダウンロード
$ ATLANTIS_VERSION=v0.21.0
$ wget -o - https://github.com/runatlantis/atlantis/releases/download/$ATLANTIS_VERSION/atlantis_linux_amd64.zip
unzip atlantis_linux_amd64.zip

## Atlantisパラメータの設定
USERNAME=atlantis-user
SECRET=(作成したGitHub webhookのシークレット)
TOKEN=(作成したGitHUbのトークン)
URL=(cloudflared実行時にメモしたURL)
REPO_ALLOWLIST=(GitHubリポジトリ)(ex. github.com/example/atlantis-example)

## Atlantisの実行
./atlantis server \
--atlantis-url="$URL" \
--gh-user="$USERNAME" \
--gh-token="$TOKEN" \
--gh-webhook-secret="$SECRET" \
--repo-allowlist="$REPO_ALLOWLIST"

AtlantisのURLにアクセスしてみます。

Atlantisの画面表示

Atlantisの画面表示が確認出来ました。正常に接続出来ていそうです。

Kubernetes上に構築する

それでは実際のホスティングの基盤となるKubernetes上に構築します。Kubernetesの環境情報は以下となります。

HW: Raspberry Pi4 Model B x3 (ControlNode x1, WorkerNode x2)
OS: RaspberryPi OS 11
Kubernetes Version: v1.25.4
ContainerRuntime: cri-o

Cloudflare Tunnel の構築

Cloudflare Zero Trust公式ページでTunnelの作成方法がサポートされています。 単純構成の場合とは異なりカスタムドメインによるアクセスを行いたいため、アカウントを作成して各種設定を行います。

Tunnelの作成

  • Tunnel名の決定
    • 任意のTunnel名を決定します。
  • Cloudflaredの環境を選択
    • Cloudflaredをデプロイする環境を選択します。今回はコンテナを用いるため「Docker」にします。--tokenで指定されているトークンをメモしておきます。
  • カスタムドメインと内部ドメインの紐づけ
    • 公開するカスタムドメインと内部のドメインの紐づけを行います。内部のドメインはServiceに割り当てられるKubernetesが管理するDNSレコード( (my-service).(my-namespace).svc.cluster.local)を利用します。

Kubernetes への構築

デプロイ方法も公式ページでサポートされています。今回はこちらの Kubernetes の手順を参考に進めます。構築に使用したファイルはこちらに置いてあります。

  • Deployment
  • Secret

GitHub の Webhook の設定変更

先ほど設定したWebhook URLを公開するカスタムドメインに変更します。

Atlantis の構築

Atlantis公式ページで構築方法がサポートされています。HelmChartがサポートされているため使用しようと思いましたが、今回はIngressサービスが不要なため、サンプルマニフェストとして提供されているStatefullsetを使用し、加えて必要なリソース(+αと表記)を構築します。同じくこちらに構築に使用したファイルを置いています。

  • Statefulset
  • (+α)Service
  • (+α)Secret
  • (+α)StorageClass
  • (+α)PersistentVolume

Atlantis Dashboard にアクセス

デプロイ完了後に今回使用したカスタムドメインにアクセスをしてみます。

カスタムドメインで接続したAtlantisの画面表示

Atlantisのロゴが表示された画面が表示されたことを確認します。「DISABLE APPLY COMMANDS」というボタンはグローバルロック機能を持っていて、リソースの変更内容の適用を制限することができます。インターネットに公開しているため、このページにアクセスしたユーザー全てにボタンが見えてしまうので対処したいところです。これは後ほど対応します。

GitHubでプルリクエストを作成する

実際にプルリクエストを作成して動作を確認します。null_resourceを用いて確認します。

プルリクエストをトリガーとした terraform plan の実行

プルリクエストを作成すると、自動でterraformコマンドが実行されたことが分かります。atlantis apply -d . で適用します。

terraform apply によるリソース構築

これで一連の流れを確認することができました。

Cloudflare でのアクセス制限

グローバルロック機能のボタンのケアを行います。今回はCloudflare側の機能でケアを行います。

Cloudflare Zero Trustは今回使用したTunnel以外にも多数の機能があり、登録したサイト情報(Cloudflareエッジにおけるオリジン=ローカルサーバ)に対してWAFを定義することができます。今回はこのWAFを利用しIPアドレス制限をかけ、限られたIPアドレスのみがDashboardにアクセスできるようにします。登録するIPアドレスは、AtlantisにWebhookを送付するGitHub Webhooksが使用するIPアドレス帯とします。 GitHub WebHooksが使用するIPアドレス情報は公開されているため、こちらを参考に設定します。

よくある話として、使用されるIPアドレスは定期的にローテーションし変更される可能性があるため、業務で運用する場合などは変更に気づけるしくみが必要になる場合もありそうです。今回は個人運用ということもありそのケアは行いません。

まとめ

今回は、クラウドインフラストラクチャのコード管理の効率化を目的とした、Atlantis+Cloudflare Tunnelの構築内容をご紹介しました。

まずは、Kubernetesの基盤で稼働させることができたことに満足しています。今回使用したAtlantis/Cloudflare Tunnelは基本的な設定の他にも便利な機能があるため、引き続きカスタマイズを行っていく予定です。また、この作業の中で得た知見を業務に生かすことができればと考えています。

P.S.

採用

虎の穴では一緒に働く仲間を募集中です!
この記事を読んで、興味を持っていただけた方はぜひ弊社の採用情報をご覧下さい。
yumenosora.co.jp

LINEスタンプ

エンジニア専用のメイドちゃんスタンプが完成しました!
「あの場面」で思わず使いたくなるようなスタンプから、日常で役立つスタンプを合計40個用意しました。
エンジニアの皆さん、エンジニアでない方もぜひスタンプを確認してみてください。 store.line.me