はじめに
最近、Chromebookを買ったり複数端末で作業することが多いので、開発環境をクラウド化できないかと思案しています。
「完全にクラウドで完結する無料の Web 開発環境 2020 年春」に紹介されている通り、VS Code Onlineを使うとクラウドな開発環境がさくっと構築できます。他にもGitpodとかEclipse Cheとかもありますね。ただ、どれもSaaS版は使い勝手が微妙と言うかある程度お作法を守る必要があったり、フルカスタマイズ出来るようにCheを自前で構築しようとすると結構面倒だったりしたのですが、Eclipse Theiaが良さそうだったので、GCPにインストールしてみました。
この記事自体はタイトル的にはGCPにCloud IDEを立てる話なのですが、なんだかんだでGCPにDockerコンテナを使って簡単なIAPによる認証付きアプリをデプロイする方法のチュートリアル、としても使えると思うので良ければその観点でもご参考ください。
Eclipse Theia
Eclipse TheiaはVS Codeをよりvendor-neutralな形で開発/利用できるようにしたEclipse Fundationによるクローンです。
VS CodeはBSDライセンスでGithubにありますが、MSが出しているVS Codeバイナリはマイクロソフトの商用ライセンスに従ってるとかあったり開発の意思決定プロセスとかたぶんそう言うのを気にしてよりベンダーニュートラルなクローンを作った感じだと。
まあ、細かなは背景はさておきTheiaの特徴はElectonベースのデスクトップ版だけではなくWebアプリケーション版も配布されていると言うことです。
実際、Eclipse CheやGitpodもTheiaがエディタ部分に利用されています。見た目だけではなく、VS Codeともプラグイン(LSP)レベルで互換性があるので、既存のVS Codeエコシステムがそのまま利用できるのが最大の利点です。
GCPのネットワーク設定
まず、クラウド環境の構築に先立ってネットワークの設定を行います。クラウドというと作成したサーバがどこからでもアクセスできるイメージもありますが、実際はVPCと呼ばれるネットワークの中でFWに守られています。
なので、インストール前にネットワークの設定をしておきます。
Cloud NATの作成
GCPのようなクラウド環境では各端末にGlobal IPを振って直接アクセスすることはできます。ただ、Cloud IAPと相性が悪かったりもするので通常はオンプレミスと同様にprivate IPだけをふる運用にするのが一般的です。
今回もそのポリシーで作りますが、その場合は直接インターネットに繋がらないのでdocker pull
などをするためにNATが必要になります。
GCPにはフルマネージドのCloud NATがあるのでそれを下記コマンドで作成します。
$ gcloud compute routers create nat-router-jp \
--network default \
--region asia-northeast1
$ gcloud compute routers nats create nat-jp \
--router=nat-router-jp \
--auto-allocate-nat-external-ips \
--nat-all-subnet-ip-ranges \
--enable-logging \
--region asia-northeast1
GCPのCOS(Container-Optimized OS)にインストール。
続いてTheiaをGCEにインストールします。インストールマニュアルに従ってNode.jsから入れても良いのですが、コンテナがあるのでコンテナを使います。
GKEを使っても良いですが開発環境を動かすだけには大仰なので、COSにインストールします。
COSは/var
配下とか特定のディレクトリしかデータが永続化しないのでコンテナにマウントする用のディレクトリを起動時スクリプトで作成しています。
権限もTheiaが動くコンテナからも書き込めるように777にする必要があります。真面目に作るときはPDを使う方が良いかもです。
# !/bin/bash
mkdir -p /var/theia
chmod 777 /var/theia
次にgcloud
コマンドでGCEにインストールします。create-with-container
でコンテナを指定して自動起動にします。
$ gcloud beta compute instances create-with-container \
ins-theia \
--zone=asia-northeast1-b \
--machine-type=e2-standard-2 \
--preemptible \
--subnet=default --no-address \
--tags=theia \
--image-family=cos-stable \
--image-project=cos-cloud \
--container-image=theiaide/theia:next \
--container-restart-policy=always --container-privileged \
--container-mount-host-path=mount-path=/home/project,host-path=/var/theia,mode=rw \
--metadata-from-file startup-script=config.sh
NAME ZONE MACHINE_TYPE PREEMPTIBLE INTERNAL_IP EXTERNAL_IP STATUS
ins-theia asia-northeast1-b e2-standard-2 10.146.0.23 RUNNING
オプションに特筆することは無いですが、前述の通りグローバルIPはふってません。また、nested containerをしたいのでprivilegedを付けています。開発環境なので普通にDockerを動かしたいですからね。
また、Dockerに対してポートバインディングの設定もしていません。COSではコンテナはホストネットワークで動いてるので単にVPCに穴を開けるなどすれば直接見れるからです。詳しくはこちら。
これで構築は完了です。正常にインストールが出来たか動作確認をしてみます。
Private IPだけなのでIAPを使ってポートフォーワードをします。まずはIAPから先ほど作ったサーバにアクセスできるようにタグに対してFirewallに穴を開けます。
$ gcloud compute firewall-rules create allow-iap-theia \
--network=default \
--target-tags=theia \
--allow=tcp:3000 \
--source-ranges=35.235.240.0/20
続いて、IAPでポートフォーワードをします。
$ gcloud compute start-iap-tunnel ins-theia 3000 --local-host-port=localhost:3000 --zone asia-northeast1-b
Testing if tunnel connection works.
Listening on port [3000]
無事構築が出来ていれば以下のようにTheiaに繋ぐことができます。
ロードバランサの設定をする
毎回ポートフォーワードをするのは面倒なので、Cloud Load Balancingの設定をします。これはGoogleの誇る実質無限のキャパシティを持つL7のロードバランサ/リバースプロキシです。
Cloud Load Balancingには下記の作業が必要です。
- バックエンドの作成
- インスタンスグループの作成
- 名前付きポートの作成
- ヘルスチェックの作成
- バックエンドサービスの作成
- バックエンドサービスへの登録
- ホストとパスのルールの作成
- フロントエンドの作成
- 証明書の作成
- Proxyの作成
- フォーワードルールの作成
ちょっと多いですね。またフロントエンドはHTTPで作ることもできますがセキュリティを考えるとHTTPSにするべきです。
ただ、その場合は証明書の発行にドメインが必要です。nip.ioのようなワイルドカードDNSを使うか、お名前.comやGoogle Domainsで独自ドメインを取得する必要があります。
個人的にはドメインを持っておくとCloud Identityが使えたりと便利な事が多いので、年間で1500円から2000円くらいなので、これを機に買っておくのも良いと思います。
バックエンド サービスの作成
まずバランシング対象であるバックエンドサービスを作ります。
バックエンドサービスはインスタンスではなくインスタンスグループにする必要があります。
今回はすでにインスタンスを作っているので、非マネージドなインスタンスグループを作って参加させます。
またこのインスタンスグールプではtheiaがポート3000で待ちつけているので名前付きポートを作成します。
$ gcloud compute instance-groups unmanaged create ins-group-theia --zone=asia-northeast1-b
$ gcloud compute instance-groups unmanaged add-instances ins-group-theia --zone=asia-northeast1-b \
--instances=ins-theia
$ gcloud compute instance-groups unmanaged set-named-ports ins-group-theia --zone=asia-northeast1-b \
--named-ports=port-theia:3000
続いてバックエンドサービスの死活監視を行うHealth Checkを作ります。
$ gcloud beta compute health-checks create http http-check-theia --port 3000 --request-path '/' --global --enable-logging
ただこの状態ではHealth Checkリクエスト自体がFirewallで止められてるのでGFEからtheiaへ穴を開けます。GFEからロードバランシングの実施やヘルスチェックが行われます。
$ gcloud compute firewall-rules create allow-gfe-theia \
--network=default \
--target-tags=theia \
--allow=tcp:3000 \
--source-ranges=35.191.0.0/16,130.211.0.0/22
最後にバックエンドサービスを作成してインスタンスグループを追加します。
$ gcloud compute backend-services create backend-theia \
--protocol HTTP \
--health-checks http-check-theia \
--port-name port-theia \
--global
$ gcloud compute backend-services add-backend backend-theia \
--capacity-scaler=1 \
--instance-group=ins-group-theia \
--instance-group-zone=asia-northeast1-b \
--global
URLマップとフロントエンドの作成
まず、SSL証明書を作ります。特にこだわりが無いのでGoogleが無料で発行/管理してくれるGoogle マネージド SSL 証明書を使います。
$ gcloud beta compute ssl-certificates create cert-theia \
--description="certificates for theia" \
--domains=${YOUR_DOMAIN} \
--global
$ gcloud beta compute ssl-certificates list --filter="name=cert-theia"
statusがPROVISIONING
からACTIVE
なればOKです。これは少し時間がかかります。
次にURLマップを作成します。以下のコマンドで全てのリクエストをbackend-theiaに飛ばすマップを作ります。
$ gcloud compute url-maps create lb-theia --default-service backend-theia
アクセスを受けるエンドポイントとなるProxyを作成してリクエストを流すフォーワードルール(フロントエンドサービス)を作ります。
$ gcloud compute target-https-proxies create proxy-theia \
--url-map lb-theia --ssl-certificates cert-theia
$ gcloud compute forwarding-rules create frontend-theia \
--global \
--target-https-proxy=proxy-theia \
--ports=443
今回IPアドレスは自動作成にしたので以下のコマンドで確認して、DNSに登録します。
$ gcloud compute forwarding-rules list
NAME REGION IP_ADDRESS IP_PROTOCOL TARGET
frontend-theia xxx.xxx.xxx.xxx TCP proxy-theia
これで、https://${YOUR_DOMAIN}/
にアクセスできれば完了です。DNSの反映などは少し時間がかかると思います。
Cloud IAPの設定
最後にIAPの設定です。
現状は誰でもアクセスできてしまうので認証を掛けたいです。
ただ、ネットワークACLだとカフェとかからアクセスできませんし、Basic認証だとちょっと弱すぎます。Theia自体に認証の機能もありません。こういう時にはIdentity-Aware Proxy(IAP)が有効です。
IAPはその名の通りコンテキストを判定するProxyです。コンテキストとはユーザ、ロール、ロケーション、ターゲットアプリケーションを指します。RBACより高度なCAACを実現しGoogleのゼロトラストセキュリティ/ByondCorpの中核です。ゼロトラストセキュリティ自体の詳しい話は以前書いたブログがあるのでそちらを参考ください。
今回はIAPをURLに適用する事で自分だけがアクセスできるように設定します。
OAuth同意画面の作成
まず、OAuth同意画面の設定をします。サポートメールは適当なGoogle Groupを作っておくと自分のgmailを晒さなくて良いと思います。
OAuth認証情報の作成
次にOAuth認証ページに移動してOAuth 認証情報の作成を作成します。
Googleの公式ページを参考に以下の手順を実施します。
- 認証情報の作成] プルダウンリストを開き、[OAuth クライアントID] を選択します。
- [アプリケーションの種類] で、[ウェブ アプリケーション] を選択します。
- OAuth クライアント ID の名前を追加します。
- [作成] をクリックします。OAuth クライアント ID とクライアント シークレットが生成され、OAuth クライアント ウィンドウに表示されますのでメモします。
- [OK] をクリックします。
IAP アクセス権の設定
IAPがバックエンドサービスにアクセスできるようにFirewallの設定を変更します。
$ gcloud compute firewall-rules update allow-gfe-theia \
--target-tags=theia \
--allow=tcp:3000,tcp:80 \
--source-ranges=35.191.0.0/16,130.211.0.0/22
以下のコマンドでバックエンドサービスに対してIAPを有効にします。
$ export OAUTH2_CLIENT_ID=xxxxx.apps.googleusercontent.com
$ export OAUTH2_CLIENT_SECRET=xxx
$ gcloud compute backend-services update backend-theia --global --iap enabled,oauth2-client-id=${OAUTH2_CLIENT_ID},oauth2-client-secret=${OAUTH2_CLIENT_SECRET}
以下のように、アクセスができなくなれば成功です。

最後に自分のアカウントに閲覧権限を付けます。
$ export YOUR_GMAIL=xxxx@gmail.com
$ gcloud iap web add-iam-policy-binding --resource-type=backend-services \
--service=backend-theia \
--member=user:${YOUR_GMAIL} \
--role=roles/iap.httpsResourceAccessor
これでTheiaがIAPで保護されるようになりました。
まとめ
GCPにTheiaを入れて簡単なCloud IDEを作ってみました。
もちろんSaaSを使う方が何かと手っ取り早いとは思うのですが、自分でこうして環境を作るのも楽しいですよね。
実際にDokcerビルドや実行したりとかの開発をこの環境を使っていって、後世のカスタマイズもしていきたいと思います。
あと、COSはk8s使うよりも手軽なのでIAPと組み合わせてOSSツールをさくっと入れるのにやはり便利ですね。
それではHappy Hacking!