GitHub Codespaces便利。
そんな便利なGitHub Codespacesのオレオレ版をAzure Container Appsを使って作ってみた。
GitHub Codespaces自体のソースコードは公開されていないので、code-serverというオープンソース版を使ってみる。
ちゃんとコンテナーイメージも公開されているから試すのもカンタン。
Azure Container Appsにデプロイしてみる
動かしてみるのは簡単。
Container Appリソースを作ってコンテナーイメージの設定に👆で公開されているイメージを設定して、ターゲットポートに8080を設定するだけ。
Container Appリソース作成&コンテナーイメージ設定
コマンドだとこれ一発であっさり起動する。
az containerapp create \ --name $CONTAINERAPPS_NAME --resource-group $RESOURCEGROUP_NAME \ --environment $ENVIRONMENT_NAME --ingress external \ --image docker.io/codercom/code-server:$TAG --target-port 8080
Container AppリソースができたらURLにアクセスしてみると起動したのがわかる。
パスワード認証を無効にする
デフォルトでパスワード認証が有効なので、必ず認証画面 /login
にリダイレクトされ、パスワード入力画面が表示される。
このパスワード認証は無効にできるので、Azure Container Apps自体の認証機能など別の仕組みで認証する場合は無効にした方がいい。
無効の仕方は、
- 👆のスクショに書かれている設定ファイル
/home/coder/.config/code-server/config.yaml
に書く
or - コンテナーの起動時にオプションとして渡す
のどちらか。
設定ファイルはコンテナの一部になっていて、サクッと試すには手間なので、今回はコンテナー起動時にオプションを使ってみる。
以下のコマンドで組み込み認証を無効にする。
az containerapp update \ --name $CONTAINERAPPS_NAME --resource-group $RESOURCEGROUP_NAME \ --args="--auth=none"
これでお馴染みの画面が出てくる。
※
割とハマったのが--args
オプション追加の顛末はこちら--args
オプションの追加。
他のコマンド同様 --args "--auth=none"
とみたいにスペースで区切ると、--auth
の方も別オプションとして認識されてしまい「そんなオプションはない」と怒られる。
あと--auth=none
の方も、ローカルのDockerで試した時は--auth none
とスペース区切りで指定しても問題なくパスワード認証が無効にできたけど、Container Appリソース上のコンテナー起動の引数として渡す時は=
で繋げないとダメだった。
いくつかパターンを試した結果、--args="--auth=none"
に落ち着いた。
引数の処理が違うんだろうか。
このあともう一回ハマる。
code-serverコンテナーを増やしてみる。
想定しているのは、複数のユーザーが同時に使うシーン。
なので、増やすといってもスケールアウトさせるのではなく、Container Appsリソースを増やして、そのユーザー専用code-serverにする、という構成。
参考にするのはこの公式ブログ。
このブログで紹介されている下図の構成、
この図のフロントエンド(nginxを動かすContainer Appリソース&ingressはexternal)はそのまま拝借。
その後ろのバックエンドapp1
~appN
のContainer Appリソース(ingressはinternal)がcode-server1~code-serverNになり、それぞれユーザー毎のcode-serverが動く感じ。
WebSocketが動かない???
👆のブログ内に構成する手順が書いてあるので、まずはこれを参考にフロントエンドのnginxの設定を試してみる。
events { } http { server { listen 80; location /code-server1/ { proxy_http_version 1.1; proxy_pass http://${CODE_SERVER1_NAME}/; } } }
フロントエンドの/code-server1/
というパスへのリクエストを、バックエンドのContainer Appリソース${CODE_SERVER1_NAME}
にフォワードする、いわゆるリバースプロキシ用設定。
これをフロントエンドのContainer Appリソースのnginxに適用して、実際にアクセスしてみると、、、
はい、エラー。ですよね。
そう簡単にいかないのは重々承知。
エラーメッセージはWebSocketが繋がっていない、って言ってるので、「nginx リバースプロキシ websocket」で検索。
出てくる情報は「nginxでクライアントとバックエンドのWebSocket通信を仲介する時はリクエストヘッダーを追加しよう」的なもの。
これを基にnginx.confを修正したのがこちら。
events { } http { server { listen 80; location /code-server1/ { proxy_http_version 1.1; proxy_pass http://${CODE_SERVER1_NAME}/; # 以下を追加 proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } } }
${CODE_SERVER1_NAME}
はバックエンドのContainer Appリソース名に適宜置き換えてもらって。
追加したのはUpgrade
やConnection
のヘッダー。
これでうまくいけば、と祈りつつ再びアクセスしてみると、、、
ダメ。エラー変わらず。
この後「proxy_ssl_server_name on;
を付けるとうまくいく」的情報を見つけて試してみるもエラーは変わらず。
いろいろ試すのに疲れたので、初心に返って「バックエンドにつながってエラーになってるのか、フロントエンドでブロックされてるのか」というところから確認。
Azure Container Appsの標準出力はAzureポータルのLog Streamで確認できるので、code-serverがデバッグログを出すよう、起動時の引数に--verbose
を追加。
※再び
--verbose
追加の顛末はこちら--auth=none
と--verbose
の両方を設定しないといけなかったので、まずは--args="--auth=none --verbose"
とやってみたけどダメだった。
他にも、--args="--auth=none""--verbose"
とか--args=["--auth=none","--verbose"]
とか、雰囲気で複数指定できそうなパターンをいくつか試したものの、片方しか効かない、とか、両方とも効かない、とか。
結局az containerapp update
一発でやるのは諦めて、
az containerapp show
でARMテンプレートを取得- テンプレート内の引数
args
に相当する箇所を修正 3.az containerapp update
でテンプレートを丸ごと適用
という手順で何とかパスワード認証無効&デバッグログ出力できた。
にしても、公式ドキュメントには、
コンテナーのスタートアップ コマンド引数の一覧。 スペース区切りの値 (例: "-c""mycommand")。
とあるけど全然効かない。
未だに正しい指定方法がわからない。
大量に出てきたエラーがこちら。
debug host "(バックエンドのContainer App名)" does not match origin "(フロントエンドのホスト名)"; blocking request to /stable-c26ac35b25b09e9d58e6716f2aae41d8d1dfbb6c?reconnectionToken=b6a8c9eb-6f4f-448a-bb0c-faabe3efef0d&reconnection=false&skipWebSocketFrames=false
あ、originがあってない、ってことね。
ていうか、origin見てるのね。
というわけで、Originヘッダーを追加。
events { } http { server { listen 80; location /code-server1/ { proxy_http_version 1.1; proxy_pass http://${CODE_SERVER1_NAME}/; # 以下を追加 proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; # さらに以下を追加 proxy_set_header Origin http://${CODE_SERVER1_NAME}; } } }
${CODE_SERVER1_NAME}
はバックエンドの(以下略)。
これをフロントエンドのnginxに反映すると、無事nginx経由でバックエンドのcode-serverを開くことに成功🎉🎉
やっぱりログ重要。
今後やらんといかん事
今回はとりあえず動いたことを確認したまで。
けど実際使うとしたらいろいろやること、確認すること多そう。
例えば、
などなど。
時間見つけてやっていこう。