いしぐめも

プログラミングとかしたことを書きます。

ストレージアカウントのプライベートエンドポイント作成でFunctionsへのデプロイができなくなった問題

何を言っているのかわからねーと思うが・・・

背景

ストレージアカウントにプライベートエンドポイントを設定して、
関数アプリからVNET経由でアクセスするようにしようとしていました。

すると・・・デプロイが不安定になりました

デプロイが不安定になった!

なんじゃそりゃって感じだと思うんですが、「不安定」としか形容できない状態になりました。

まず、VSCodeのAzure Functions Extensionからデプロイできない

今までできていた、Bastion内へVSCodeリモートで乗り込んで叩いていた
Azure Functions拡張機能でのデプロイができなくなりました。

「デプロイ成功」みたいなメッセージがでるのに、関数アプリの「概要」画面では何の関数も表示されない・・・

Azure Functions Core Toolsでデプロイできるときとできないときがある

なんじゃそりゃ・・・再現条件不明です

原因(たぶん)

プライベートエンドポイント設定を行うとき、あわせてDNS設定を行うと思いますが、
そのDNSレコード設定のIPアドレスを自動で設定してくれる「privateDnsZoneGroups」という便利なリソースがあるんですが、それの設定をミスっていました・・・

blog.aimless.jp

直接的な原因はコピペミスです・・・

ストレージアカウントのプライベートエンドポイントは使用しているリソースごとに設定する必要があります。
今回のケースでは「blob」「queue」「table」でそれぞれプライベートエンドポイントを設定する必要があり、
横着してコピペしたところqueueのprivateDnsZonesに向けて作成すべきprivateDnsZoneGroupsをblobのものに向けて作成しまうというありえないミスをしていました。

結果、FunctionとFunctionの動作に必要なストレージ間での接続に何らかの問題が起こってデプロイできなくなってしまったんじゃないかな?と考えています(わかりませんが)。

結論

コピペには気をつけよう!

bicep便利 vscode便利!

最近はAzure上にリソースを構築したり破壊したりを繰り返していますが、bicepはとても便利です。
ハマりどころさえうまく回避(解消)できればとても強力なツールとして役立てることができますので、
出せるTipsは出していろんな情報が出回るようになるといいなと思いました。

また、VSCodeのAzure拡張もすごく便利ですね。もともとVSCodeのリモート機能が便利なのは知っていたんですが、
BastionのVMに乗り込んで、Azure拡張でそのままVNET経由でFunctionsへデプロイすることができるのは知りませんでした・・・!
認証もVSCodeが代替してくれるので、 GitHubへのログインやAzureへのログインを省略でき、とても捗るのでオススメです。

HTMXでmorphdomを使ってDOMの入れ替えをせずに更新する

あんまり凝ったことをHTMXでやるべきではないというのが持論ですが、どうしても足したい機能があって、HTMXがDOMを入れ替えてしまうことが問題になるケースではmorphdomを使うときれいに解決できるかもしれません。

HTMXとは

HTMXとは、タグに hx-hogehoge といった属性を足すことで、HTMLだけを書いているように見せつつも動的にDOMを組み立てることができるライブラリ。

ちょっとした情報更新がある動的サイトを書きたいときはとてもスッキリ書けるので、結構画期的なライブラリに思えます。

が、書くには結局DOMから発せられるイベントに熟知している必要があるなど、よく言われる「JavaScript書かなくていい」みたいなのはちょっと全面的には肯定できないですね。「JavaScriptをよく知ってる人が頑張って工夫すると簡潔に書ける」ぐらいが関の山かなと思います。

個人的にこのライブラリは、バニラなJavaScript+bootstrapで構成されたサイトを置き換えるシーンで活躍しそうだなという感じがします。

DOMが入れ替わってしまうと何が起こるのか

HTMXは、デフォルトの動作では、指摘したターゲット(要素)を取得したHTMLで書き換えるという動作をします。この書き換えは基本「入れ替え」となりますので、以下のようなことが起こります。

  • 画像の再読み込み
  • カーソル位置のリセット
  • イベントのバインドの解除

要はまったくの新しい要素が追加されるということなので、要素の入れ替わりが起こった時には毎度ページを読み込んだ時のように初期化を行ってあげる必要が出てくるわけです。

ここらへん、Reactで頑張って再レンダリングを抑止!とか普段やってる人間からすると「うおお気持ち良くない」となるポイントですが、受け入れるほかありません。

代替の方法 morphing

前章では「デフォルト動作では入れ替え」と書きましたが、入れ替え以外の方法として 「morphing」 という方法があります。morphとは「変化させる」という意味の英単語ですが、すでにあるDOMを指定された状態に置き換えではなく、変更する(morphing) ということをします。

morphingを行った結果は同じHTMLになるので、見た目的には同じものができますが、新しいものに差し変わるわけではないので状態が保存されます

デメリットとしてはガバッと雑に差し替えるわけではなく、既存要素を舐めて変更箇所を見つけるので、単純な置換よりは重たい処理になるというのが挙げられます。まぁただ、HTMXでかかる変更はHTTP通信を伴うので、そもそも通信の時間を考えると置換にかかる時間は微々たるものという考え方もできなくはないので、毛嫌いするのではなくやってみて影響度合いを確認するのがよいでしょう。

HTMXでmorphingできるように拡張を書く

DOMのmorphingを実現するライブラリとして「morphdom」というものがあります。

GitHub - patrick-steele-idem/morphdom: Fast and lightweight DOM diffing/patching (no virtual DOM needed)

このmorphdomですが、HTMXではそれ用の拡張機能が提供されていて、簡単に導入することができます。

htmx-extensions/src/morphdom-swap at main · bigskysoftware/htmx-extensions · GitHub

morphdomがそのまま使えればいいよ~というケースでは上記で十分です。

つかいかた

使い方については上記拡張機能のリンクに書かれているのでそちらを参照してください。

終わりに

今回はHTMXでmorphingすると便利だよという内容で書かせていただきました。

morphdomを使用してのswapは要素の入れ替わりを抑止することができるので、拡張機能を導入するだけで

  • 画像が再読み込みされない
  • カーソル位置が保持されたまま
  • イベントのバインドが解除されない

といったメリットを得られます。

実際の使用では、JavaScript経由で追加した「要素のクラスもキープしたい」という要望もあったので、拡張機能をさらにいじって、属性で指定した要素のクラスを不変にするといったことも行いました。

htmx.defineExtension('morphdom-swap', {
    isInlineSwap: function (swapStyle) { /* 略 */ },
    handleSwap: function (swapStyle, target, fragment) {
        if (swapStyle === 'morphdom') {
            /* 中略 */
            morphdom(target, targetFragment, {
                onBeforeElUpdated: function (fromEl, toEl) {
                    /* fromEl から toEl へクラスをコピーする */
                    return toCls;
                }
            });
            return [target];
        }
    }
})

上記内容についてはmorphing自体の内容から逸れてしまうのでメインには書きませんでしたが、morphdom使用を契機に拡張機能自体にもチャレンジする機会を得ることができました。

個人的にあんまりゴリゴリJavaScript書いたり、それのために拡張機能を書いたりするのは、HTMXの特徴である「JavaScriptを意識せずに書ける」という点を潰してしまうのであんまり美しくないなあと思うところですが、このような対処方法もあるよということでこの記事を書かせていただきました。

長くなってしまいましたが、以上です。みなさまもよきHTMXライフを

Microsoft.Network/dnsResolvers/inboundEndpoints の subnet 指定のIDはリソースIDじゃないから注意(ARMテンプレート, Bicep)

Microsoftのドキュメントを読んでフンフンフーンとBicepを書いていたらドハマりしたので共有。

learn.microsoft.com

なにが起こったか

DNSプライベートリゾルバを使用するとき、DNSへのインバウンド通信に使用するIPを定義する「inboundEndpoints」というリソースがあるんですが、ドキュメントを読んで適当に実装すると死にます。

というのも、IP指定を行う IpConfiguration のパラメータには以下のような記載があります。

inboundEndpointsのIpConfigurationの説明

これをそのまま真に受けて、「subnet の id はリソースIDを指定すればいいんだな」と考えてしまい、

subnet: { id: inboundSubnet.id }

とか書いてしまうと、デプロイ時にエラーが起こります。

で、今回は別モジュールでbicepを書いていたので、該当デプロイのログを見ようとすると・・・

なぜかDeploymentがNotFoundになる

なぜか404…

解決方法

解決方法はサンプルにありました。

github.com

ここによると、サブネットのID指定は ${resolverVnet.id}/subnets/${inboundSubnetName}(著者編集) で行う必要があるみたいですね。

終わりに

あんまサブネットを指定するケースってなかったので今回ハマってしまったのですが、「<VNET_ID>/subnets/<SUBNET_NAME>」って指定するのが一般的なんでしょうか?

結構注意が必要ですね

Streamlit component APIに入門する

「StreamlitってReactっぽいよな~~~」って思いつつ、書けば使えてしまうので何となくで使ってきたStreamlitですが、Streamlitの動作に対して理解を深めるべく Streamlit Componentに入門してみたいと思います。

Streamlitとは

Streamlitはpythonで簡単にフロントエンドを開発できるライブラリです。Pythonのコードを書くだけで、JavaScriptで構成されたフロントエンドとPythonで動くバックエンドを作れてしまう優れものです。

Webで動作するデモアプリを書きたいときにフロントとバックエンドの通信はどうするだとか、各々のサーバーは何で構成するだとか考えなくて済むのでとても重宝します。

Streamlit Component API

Streamlitは「コンポーネント」という単位で画面を構成し、「見出し」「マークダウン」「グラフ」のような感じで何を表示していくかを順に記述していきます。デフォルトでもグラフやDataFrameを表示できるので、十分なぐらいに実装されているのですが、オレオレなコンポーネントを実装したい人向けに「Streamlit Component API」というものが提供されています。

ドキュメントはこちら↓

Components API - Streamlit Docs

自作コンポーネントを作ってみよう

というわけで、自作コンポーネントを作っていきます。極力ステップバイステップで所感を交えつつ手順を紹介したいと思います。

公式から提供されているテンプレートを使う

いきなりテンプレートのコピペとなってしまって申し訳ないですが、公式からコンポーネントのプロジェクトを作るにあたって活用できるテンプレートが提供されているので、ありがたくそれを使っていきます。

github.com

Streamlit公式から提供されているテンプレート「component-template」

画像の通り、「template(React Componentのように記述できる)」「template-reactless(React Componentを使用しないタイプ)」の2つのテンプレートがあります。今回の例ではReact Componentで試したいことがあったので、、前者を利用します。

というわけで、上記 component-template をクローンして、templateフォルダで作業をしていきます。

git clone https://github.com/streamlit/component-template
cd component-template/template

フロントエンド用の資材を準備・サーバー起動

まずは、フロントエンドはTypeScriptで記述したものをトランスパイルして使用するので、依存しているライブラリの導入が必要になります。フロントエンドのフォルダに移動して npm install を実行します。

pushd my_component/frontend
npm install
popd

ライブラリが揃ったら、npm start でサーバーを起動します。Reactユーザーにはお馴染みの react-scripts でWebサーバーが立ち上がります。

pushd my_component/frontend
npm start

開発中は react-scripts で適宜トランスパイルされてWebサーバーで公開されているものを読み取りに行く動きをするようですね。

Streamlitで動作確認する

Streamlit で my_component/__init__.py を実行することで動作確認することができます。

streamlit run my_component/__init__.py

起動すると 8501 番ポートで立ち上がるので、そこにアクセスすると動作している様子を確認することができます。

vscode で devcontainer を使用している場合、vscodeのポートフォワーディングでlocalhostの8501にポートがバインドされるので、ブラウザで http://localhost:8051 を開けばOKです。

VSCodeのポートフォワーディングでコンテナ内のポートにアクセス

Streamlit Component動作確認!

リリースする方法

ソースコードを見てもらえるとわかりますが、_RELEASE 変数の値によって動作が変わるようで、「_RELEASEがFalseの時はローカルサーバーを参照」「_RELEASEがTrueの時はトランスパイル済みのjsファイルを参照」するように動作が変わるみたいです。

なぜわざわざローカルサーバーを参照?ってところですが、これはまぁコンポーネントのソースコートが更新された時にホットリロードされるように、ということなのかなと思います。

_RELEASE をTrueにするとトランスパイル済み資材が参照されるので、これは別途 npm run build でトランスパイルしてそれを含めてモジュール化するという流れになるみたいです。これは公式のワークフローを参照するといいと思います。(ソースコード内の_RELEASE変数書き換えからやってて勉強になります。)

component-template/.github/workflows/ci.yaml at master · streamlit/component-template · GitHub

devcontainer化しました

と、ここまでの内容(+これから以下で試す内容)をdevcontainer化しました。

とはいえ、求められるのはnodeとpythonだけなので、いうほど環境準備はハードル高くないかなと思いますが。ローカル環境汚したくないよって人はぜひ使ってみてください。

GitHub - yoh1496/learning-streamlit-component: Repository for learning streamlit component

気になったこと

個人的に試して気になったことを書きます。(順次書き足していく予定です)

気になったことその1: マウントアンマウントは検知できる?

Streamlit ComponentはReact Componentライクに書くことができるので、Reactのライフサイクル同様、componentDidMount などの関数が呼ばれるかを試してみました。コンポーネントのアンマウント時にクリーンアップなどの処理ができると便利ですよね。

class MyComponent extends StreamlitComponentBase<State> {
  public state = { numClicks: 0, isFocused: false }

  public componentDidMount(): void {
    super.componentDidMount()
    console.log('mount');
  }

  public componentWillUnmount(): void {
    if (super.componentWillUnmount) super.componentWillUnmount();
    console.log('unmount');
  }

  public componentDidUpdate(): void {
    console.log(this.props)
  }

/** 略 **/

というわけでこんな感じに実装して、以下のようにマウント・アンマウントを試すコードを書いてみました。

    if 'mounted' not in st.session_state:
        st.session_state.mounted = False

    def on_click_unmount():
        st.session_state.mounted = False
        del st.session_state.hoge
    
    def on_click_mount():
        st.session_state.mounted = True
    
    mounted = st.session_state.mounted

    st.button('Unmount Component', disabled=not mounted, on_click=on_click_unmount)
    st.button('Mount Component', disabled=mounted, on_click=on_click_mount)

    if mounted:
        my_component('Mount/Unmount Test', key="mount_unmount_test")

session_state を用いてmountedフラグを管理し、mountedフラグの値によって表示/非表示を切り替えるコードです。

結果

これを実行した結果、componentDidMount, componentDidUpdate は呼ばれるが componentWillUnmount は上記pythonスクリプトでは呼ばれないことがわかりました。

この結果では 「非表示にしただけではStreamlit Componentはアンマウントされない」のか「Streamlitではアンマウントに際してcomponentWillUnmount` は呼ばれないのか」は不明ですが、ちょろっとコードを書くだけではアンマウント時の動作を記述することは難しいということは言えそうです。

どなたかアンマウントにあわせて処理を記述する方法をご存じの方がいらっしゃいましたら教えていただければ幸いです。

終わりに

今回はStreamlitをよりカスタマイズするために、Streamlit Componentを試してみました。

冒頭にも書きましたが、Streamlitはちょっとオタメシのフロントエンドを書くのにすごく便利で、Componentと組み合わせることで標準のStreamlitにはない機能を持たせることができることがわかりました。

個人的にはこれからも便利にStreamlitを使っていきたいなと思うところですが、いろいろ複雑なことをやると死ぬ(これについてはまたいつか書きたいです)というところも同時にわかってきたので、あんまりゴチャゴチャComponentで書こうとしてReactで書いた方が結局早くね?とならないように気を付けたいところです。

【Azure Functions】ローカル開発でもカスタムコンテナーを使いたい!

Azure Functionsを利用するアプリ開発(≠Azure Functionsの開発)において、どのようにローカル開発を行うかというのは大きな課題です。

一番ベタなのは azure-functions-core-tools を使用しての開発かなと思いますが、Functions自体はコンテナ化しておきたいと考えると、ローカル開発とデプロイされるものが異なってしまうのが難点かなと個人的には思います。

というわけで、今回はローカル環境で本番と同じコンテナイメージを使って開発してしまおうという内容になります。

はじめに: カスタムコンテナーとは?

そもそも、Azure Functionsにはソースコードをコンテナに配置して、そのイメージをデプロイするというオプションがあります。

カスタム イメージを使用して Linux 上で Azure Functions を作成する | Microsoft Learn

これをドキュメントでは「カスタムコンテナー」として扱っているんですが、クラウドにデプロイして使う方法しかドキュメントには載っていません。ローカルでも使えたらきっと便利ですよね。

カスタムコンテナーで内部的に使用されているのは azure-functions-host

上記の手順に従ってカスタムコンテナーを作って動かしてみると、どうも内部的に使用されているのは azure-functions-host というものらしいです。詳細は以下のリポジトリを参照。

GitHub - Azure/azure-functions-host: The host/runtime that powers Azure Functions

これはどうやらAzure Functionsで使用されているランタイムのようで、これ公開してるのすごいなと思いつつ、仕様がオープンになっているのでありがたく使わせていただきましょう。

カスタムコンテナーをローカル開発で使用する手順

では、ここからはAzure Functionsで使用するカスタムコンテナーをローカル開発で使用するにあたって必要な手順を書いていきたいと思います。

カスタムコンテナーを作る

まずはドキュメントに従ってカスタムコンテナーを作ります。

mcr.microsoft.com/azure-functions/python などをベースに、requirementsをインストールしてソースコード/home/site/wwwroot に配置するという感じになるかなと思います。(pythonのばあい)

起動用のdocker-composeを書く

次に、起動用にdocker-composeを書いていきます。

version: '3.7'

services:
  functions:
    build: .
    environment:
      AzureWebJobsStorage: DefaultEndpointsProtocol=https;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://azurite:10000/devstoreaccount1;QueueEndpoint=http://azurite:10001/devstoreaccount1;
      AZURE_FUNCTIONS_ENVIRONMENT: Development
    ports:
      - 80:80

  azurite:
    image: mcr.microsoft.com/azure-storage/azurite
    hostname: azurite
    restart: always
    ports:
      - 10000
      - 10001
      - 10002

ローカルでキューストレージのトリガを使ったりするために Azurite というストレージアカウントのエミュレータを同時に動かすようにしています。(なくても動くかも。)

(Optional)ローカル開発時の認証を消す

azure-functions-core-toolsでは、実行時にauthLevelがanonymousになるという仕様があるんですが、このカスタムコンテナーだとそれがありません(本番環境にも同じものがデプロイされるので当然)。なので、本番はauthLevelでfunction で使うことを想定している場合にカスタムコンテナーではローカル開発では使用できないという問題が発生してしまいます。

というわけで、私は起動時の実行コマンドで以下のようにsedでauthLevelをanonymousに変更して起動するようにしてみました。

    command: >-
      bash -c '
      sed -i -e "s/\"authLevel\":.*/\"authLevel\": \"anonymous\",/" /home/site/wwwroot/hogefunc/function.json
      && /azure-functions-host/Microsoft.Azure.WebJobs.Script.WebHost
      '

実行する

作ったdocker-compose.ymlファイルを通常通り起動すればOKです。

docker-compose up

終わりに

以上、ローカル開発でAzure Functionsのカスタムコンテナーを使用するという話でした。

ユースケースとしては、

「Azure Functionsに直接乗っかるものを開発するのには azure-functions-core-tools を使用して、ある程度固まったらカスタムコンテナー化して今度はそのFunctionsを利用する側のアプリを書く」

そんな感じでうまく使い分けられると良いんじゃないかと思いました。

今回作ったdocker-compose.ymlをベースにdevcontainersで使用したりするのもGOODですね。

えっ?!全部の受信ポートを拒否しながらVSCodeでリモート開発を?!【ConoHa編】

「できらぁ!!!!」

というわけで、この記事は、ConoHa Advent Calendar 2022 20日目 の記事です。急遽20日目が空いたので、急いで書きました。

はじめに

以前、Visual Studio Code(以下、VSCode) がRemote Tunnelという新しいリモート開発方法を提供開始したという記事を書きました。

yoh1496.hatenablog.com

こちらで「「え?ベンダが提供するWeb画面ベースのコンソールでもいいの?」に対しては「はい」です」と書いたので、実際に試してみましょうという記事になります。

著者のConoHa歴

Advent Calendarからいらっしゃった方は初めまして。@yoh1496と申します。

ConoHa VPSは趣味で2年近く使ってます(主にマイクラサーバーを立てたり、リバースプロキシにしてみたり)。 最近ConoHa WINGも契約しましたが死蔵しています。PHP勉強して動くものを載せたい…

想定読者

今回の内容は 前回記事の内容と変わりありません。ですので、詳しい内容は前回記事を参照いただくとして、今回は

  • 具体的なイメージが掴みたい
  • ConoHa使った場合にどうやるのかステップバイステップで知りたい
  • ただ興味を持っただけ。ザックリ概要を知りたい

という方に読んでいただければと思います。

ConoHa での VSCode Tunnelの始め方

さて、ここからはConoHa VPSを使って、全ポート受信拒否設定をしつつVSCodeで乗り込んでみよう!という話になりますが、、、

ここからの内容は危険な可能性のある手順を含みます。
実施を推奨するものではありませんし、実施する内容を理解したうえで、実験的用途に限って試してください。

サーバーを作成する

では気を取り直して…まずはVPSを作っていきましょう。再三書かせていただきますが、万一があっても問題にならないように大事な本番環境とは分けて行ってください。

まずはいつも通りVPSを作ります

パスワードとネームタグを設定していきます。ネームタグは「vscode_dekiraa」としました。

パスワードとネームタグも設定

そして本題の「接続許可ポートを全て拒否」にします。IPv4でもIPv6でも、80番ポートはおろかSSH用の22番ポートも開きません。

接続許可ポート「全て拒否」

ここまでの基本的な設定が終わったら、code tunnelを導入すべく、VSCodeCLIのダウンロードを行うスタートアップスクリプトを用意します。ここでの内容はVPSを作成したのちに、コンソールから自身で実施いただいても大丈夫です。

今回は、お手製のスタートアップスクリプトをGistに作ってそれを読むようにしてみました。(VSCode CLIのダウンロードと、バックグラウンドでの実行を行います)

【余談】
今回初めてスタートアップスクリプトを作ってみたんですが「テキスト入力」だと「追加」ボタンを押してもVPSが作成できませんでした。これは仕様…?

https://gist.githubusercontent.com/yoh1496/47023b37b0936502992622b658182e96/raw/c04ac04ea38a836ed04d7d9a4f710cf0bbf85c7c/vscode_tunnel_start.sh

スタートアップスクリプトのURLを入力

ここまで完了したら「追加」ボタンを押してVPSを作成します。

作成されたサーバーのコンソールでcode tunnelを設定する

そして作られたVPSがコチラ。接続許可ポートに何もチェックが入っていないのがポイントです。(鉄壁の守り!)

作成されたVPS。接続許可ポートが何もない

では早速、「コンソール」に入ってみましょう。先ほどのスタートアップスクリプトを実行した後は「GNU screen」を使ってバックグラウンドでcode tunnelが動作しているので、まずは

  1. root でログインする
  2. screen -r コマンドでバックグラウンドのcode tunnelにアタッチする

をやってみましょう。

rootでログイン後、screen -r

すると、code tunnelを使用するにあたってのプライバシーポリシーやライセンスが表示されますので問題なければ「y」で同意します。

利用許諾が最初に表示される

同意すると、GitHubのアカウントとデバイス(ここではVPS)を紐づけるための認証画面へのURL(https://github.com/login/device)が出ます。

認証画面URLと8桁の認証コードが出た

それを今度はブラウザで開いてみましょう。未ログインの場合はログイン画面が出ますが、ログイン済みの場合はこの画面は表示されません。

未ログインの場合はログイン画面が出ます

表示された認証コード入力画面に先ほどのコードを入力します。

8桁の認証コードを入力する画面

すると、「aaa.bbb.ccc.dddというIPアドレスからの認可のリクエストを許可しますか」的な画面が出るので「Authorize Visual Studio Code」ボタンを押します。ここではちゃんとIPアドレスが自分が建てたConoHa VPSのものであるか確認してください。

vscodeアプリに権限を与える画面です

以下の画面が出れば(ほぼ)完了です。

接続完了!

接続用のURLを取得する

さて、ここまではGitHubの画面でデバイスとの接続を確立しましたが、いったんConoHaのコンソールに戻ります。

すると、新たに1行出力され、「このマシンになんという名前を付けますか?」と聞かれますので、いい感じの名前を付けます。(conoha_vscode_dekiraa としようとしましたが、長すぎて怒られたので vscode_dekiraa にしました)

このマシンとの接続に使う名前を決めます

そして、以下のように接続用URLが出力されればOK!これを使って接続することができます。

接続用URLが出力されます

ブラウザでVSCodeを開いてみる

ここまで準備できましたら、いざ、接続用URLを開いてみましょう。前回デバイス接続に使用したブラウザで開いてみると、、、このようにお馴染みのVSCodeが開けばOKです。

接続用URLを開くとVPS上のVSCodeにつながる!

拡張機能から開いてみる

手元のVSCode拡張機能からもやってみましょう。拡張機能で「tunnel」と検索して、出てきた「Remote Tunnels」をインストールします。

Remote Tunnels をインストール

すると、「Remote Explorer」タブで「Remote」を選んだ時に、一覧に先ほど名前を付けたマシンの名前があることを確認できると思います。

Remote Explorer に tunnels の接続対象が

名前を右クリックして「Open in Current Window」(もしくは名前右のボタン)してみると、、、

いつものVSCodeアプリで開くことができる

このようにいつものVSCodeアプリで開くこともできます。

ここからは普段通りに拡張機能VPS側にもインストールして開発するもよし、VSCodeの便利機能を活用していろいろとやってみるもよしです。

終わりに

今回は「あえて接続許可ポートを無しにしてVSCode Remoteで乗り込む」ということをやってみたわけですが、無暗にポートを開けたくないときに頑張ってWeb画面のコンソールからポチポチやっていたのを劇的に改善できる方法かなと思っています(実際どれぐらいWeb画面のコンソールが使われているかは知りませんが。。。)。ネイティブ版(アプリ版?)VSCodeを使うことで、ファイルアップロードなどもできますし、ターミナルにコピペしたりも容易ですしね。

しかし、ここで紹介したのは極端な例で、あくまでネタと考えてください。実際にはrootのままトンネル作るのは危険ですし、まじめな環境で運用をする場合はコレをしない方がよいと個人的には思います。少なくとも、ログインユーザーは分けたいところです。

というか、ここまでするなら素直にSSHできるようにした方がよい気がしますね。もちろんキッチリセキュリティ対策はするとして。やっぱりcode tunnelが真価を発揮するのはグローバルIPを持たせられない環境(例えば自宅のPC)で使う場合かなという気がしますね。

ここまで書いておいて、結局使いどころは微妙な感じかなと思ってしまいましたが、初 ConoHa Advent Calendar、お邪魔させていただきました。21日目のかた、よろしくお願いいたします~!

ではでは、みなさまもよきConoHa VPSライフを!!
(そういえば、3年間のVPSきっぷ買ったけどまだ作ったVPS活用してないや… どうしよ)

qiita.com

Visual Studio Code の Tunnel 機能が便利

Visual Studio Code に新しいリモート開発「Tunnels」が追加されました。 これが便利すぎるので、是非とも使っていきたいなと思うんですが、同時に懸念点もあるのでそこらへん書きたいなと思います。

Remote Tunnels とは

Visual Studio Code (以下、VSCode) には今までも「Remote - SSH」「Remote - WSL」「Remote - Containers 」などといったリモート開発機能が提供されてきましたが、 今回は新たな接続方法として「Tunnel」が追加されました。

code.visualstudio.com

Remote Tunnels 概要(https://code.visualstudio.com/docs/remote/tunnels から引用)

(・・・この画像見ても何がSSHの場合と変わるのかわからんw)

というわけで、公式ページで確認してみると、

  • リモート側でトンネルを作る
  • そのトンネルを経由してSSH接続が行われる
  • 認証はGitHubのアカウントを通して行われる

ということみたいです。

メリット

一番のメリットは、リモート側で「外からの通信を受ける設定を行う必要がない」ことだと思います。この「外からの通信を受ける設定」ですが、

などでしょうか。

デメリット

  • トンネルを作るにあたって、トンネルの接続先を全面的に信用する必要がある。

ことに尽きるのかなと思います。トンネル経由でSSH接続を許可するなんて、自分でバックドアを仕掛けているようなものですよね。

こういうメリット・デメリットを勘案したうえで、使用可否を判断したいところです。

使い方

ターミナルでログイン

まずはターミナルでリモート側にログインしましょう。

「え?SSHで繋げないのにターミナルでログインってどういうこと?」となると思いますが(自分もちょっと思いました)、これは 踏み台からの接続でもOK です。

「え??それってSSHで多段接続すればいい話では?」ってツッコミもあると思いますが、それはそうです。多段SSHで入れるなら多段でRemote - SSHしましょう…今回の踏み台からの接続は Azureで言うところのBastion接続みたいなの を考えてください。

「え?ベンダが提供するWeb画面ベースのコンソールでもいいの?」に対しては「はい」です。Azureのシリアルコンソールでもいけます

CLIダウンロード・展開

ログイン出来たら、「CLI」をダウンロードします。(・・・こんなの前からあった?)

https://code.visualstudio.com/Download

Download VSCode CLI

ここのダウンロードについては、ターミナル内で行ってほしいので、ブラウザで適当にダウンロード用のリンクを取得したのちに、wget なりでダウンロードしましょう。

ダウンロードできたら展開します。展開すると code というファイルが単体で出てくるので、いい感じの位置に置きましょう。(自分は ~/opt に置きました)

mkdir ~/opt
cd ~/opt
tar zxvf ../vscode_cli_alpine_x64_cli.tar.gz

トンネリング開始

展開出来たらトンネリングを開始します。

./code tunnel

すると、最初に利用許諾が表示され、GitHubのデバイス認証を行うように言われます。

GitHub Device Activation

表示されたURLを開いて、ターミナルに出てきた8桁の文字を打ち込むとcode tunnelで使用されるアカウントが紐づけられます(おそらく)

ブラウザで開く

そこまで完了するとターミナルには接続するためのURLが表示されます。それを開くと…

ブラウザ上でVSCodeが開く

こんな感じでブラウザから使えるVSCodeが開きます。GitHub Codespaces でお馴染みの画面ですね。

アプリから開く

拡張機能をインストールすることでローカルのVSCodeからも開くことができます。

marketplace.visualstudio.com

Select remote machine

できること・できないこと

もちろん、拡張機能を使用することはできます。

拡張機能のインストールと利用

これを利用することで、ちょっとしたlintを効かせながらスクリプト書いて実行したりするのには便利そうです。

が、さらに踏み込んだ使い方(ポート転送、Dev Containers)はできなさそうでした。今後に期待ですね。

使いどころ

軽く触ってみた感じ、Web開発でガッツリ使用するのは厳しいのかなという気がしました。というのも、やはりポート転送やDev Containersが使えないためです。

一方、拡張機能が使えるのはやはり強くて、軽いスクリプトを構文チェックしながら書いて実行してみるといった用途ではなかなか使えるんじゃないかなと思います。

前述した懸念点については、「開発環境での使用にとどめるべき」だと思いました。間違っても本番環境のDbをVSCode拡張機能で触るためにトンネリングで繋いじゃおうなどとは考えてはいけないですね(そんなことする人いないか)