Google Cloud Shellのカスタム環境をGoogle Cloud Shellでcloudshell envコマンドを使って用意する

Google Cloud Shell は Cloud Registory に登録した Dockerイメージ をシェルとして利用できる。これをカスタム環境 [en]と呼ぶ。

カスタム環境の開発には Google Cloud Shell に予めインストールされているcloudshell envコマンドが便利。 cloudshell env コマンドを使えば Cloud Shell 上で Dockerイメージをビルド、実行して試した後に GCP 上で自動ビルド、コンテナレジストリへのプッシュまでできる。

自動ビルド、デプロイには、Cloud Build と Cloud Source Repositories、Container Registory が使われる。

用意するもの

課金が有効になった Google Cloud Platform のプロジェクトが必要。

以下の API を有効にしておく。

  • Cloud Source Repositories
  • Cloud Build
  • Container Registory

開発環境を作る

以下は Google Cloud Shell での作業。

# 現在のセッションにGCPプロジェクトを設定する
$ gcloud config set project $PROJECT_ID

$ cloudshell env create-custom-image $REPO_NAME

$ cd $REPO_NAME

cloudshell env コマンドを実行するには、現在のセッションが GCPプロジェクトにログインしている必要がある。gcloud コマンドで現在のセッションを GCPプロジェクトにログインする。$REPO_NAMEは作成するカスタム環境の名前になる。

env create-custom-imageコマンドによって Git リポジトリが作成される

  • Cloud Source Repositories に新規 Git リポジトリが作成される
    • Cloud Shell の ~/$REPO_NAME に クローンされて origin として設定される
    • Dockerfile と Cloud Build のビルド構成ファイルが含まれる
  • Cloud Build に自動ビルドのトリガーが2つ作成される
    • このリポジトリが更新で発火
    • Goolgeが提供する Cloud Shell のベースイメージの更新で発火

作成されたことによって最初の自動ビルドが Cloud Build で実行される。ビルドが完了したら Container Registory にプッシュされる。ビルドの詳細は作成された cloudbuild.yaml に書かれている。

create-custom-image 以外の cloudshell env コマンドはこのリポジトリディレクトリで実行する必要がある。

Cloud Shellの「環境構成.イメージの場所」を変更する

cloudshell env update-default-imageで Cloud Shellインスタンスの Dockerイメージの取得元をカスタム環境イメージに設定する。作業ディレクトリのコードから自動ビルド、プッシュされる先の Container Registory のパスは cloudshell env get-image-nameで表示できる。

Dockerfileを編集する

Dockerfile を編集したらcloudshell env build-localしてビルドできるか確認する。ビルドできたらcloudshell env runでコンテナの中に入って内容を確認する、exit でコンテナからログアウトできる。

Dockerイメージを更新する

Cloud Source Repositories のリポジトリが origin として設定済みになっているので git push origin master すれば自動ビルドが実行されて Dockerイメージが更新される。

cloudshell env pushを使えば cloudshell env build-local でビルドした Dockerイメージを直接 Container Registory にプッシュすることもできる。

料金

Container Registory が使用する Cloud Storage でイメージサイズに応じた料金がかかる。Cloud Shell のベースイメージが現時点で4.5GBなので最低でも月に13円ぐらいかかる。

Cloud Build が120分/日までは無料で使える。参考として、monoのランタイムだけを追加でインストールした場合、1回のビルドが10分以内に終了した。

monoランタイムとPaketを実行できるだけのdllをインストールしたGoogle Cloud ShellのDockerイメージを作った

Google Cloud Shell で F# スクリプトを書きたかった。Google Cloud Shellには .NET Core SDK がインストールされているのでdotnet fsiコマンドで F# の REPL が使える。

nuget パッケージを使うときに Paket があると便利だが、Paket の実行には mono が必要。mono は apt でインストールができる。

Cloud Shell のインスタンスに毎回インストールしてもいいが時間がかかるので、Cloud Shell のカスタム環境として用意することにした。

カスタム環境は Google Container Registory に置いた Docker イメージを Cloud Shell として利用する。Google によって提供される Docker イメージをベースにする必要がある。提供されるベースイメージは debian 9 (strech)。

カスタム環境用の Docker イメージをビルドする Dockerfile を書いた。 mono のパッケージリポジトリと鍵を追加して、apt install で mono-runtime と必要なライブラリをインストールする。

FROM gcr.io/cloudshell-images/cloudshell:latest

RUN apt-get update \
     && apt-get install -y --no-install-recommends gnupg dirmngr \
     && export GNUPGHOME="$(mktemp -d)" \
     && gpg --batch --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF \
     && gpg --batch --export --armor 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF > /etc/apt/trusted.gpg.d/mono.gpg.asc \
     && gpgconf --kill all \
     && rm -rf "$GNUPGHOME" \
     && APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=DontWarn apt-key list | grep Xamarin \
     && apt-get purge -y --auto-remove gnupg dirmngr \
     && apt-get clean \
     && rm -rf /var/lib/apt/lists/*

RUN echo "deb http://download.mono-project.com/repo/debian stable-stretch main" > /etc/apt/sources.list.d/mono-official-stable.list \
     && apt-get update \
     && apt-get install -y \
       mono-runtime \
       libmono-system-data4.0-cil \
       libmono-system-io-compression-filesystem4.0-cil \
       libmono-system-net-http4.0-cil \
       libmono-system-runtime-serialization4.0-cil \
       libmono-system-xml-linq4.0-cil \
     && apt-get clean \
     && rm -rf /var/lib/apt/lists/* /tmp/*

Paketを実行するためのライブラリ

Paket.exe を実行するには mono-runtime だけでは足りない。mono-complete パッケージであれば十分だけど使わないライブラリもインストールされる。mono-runtime で Paket を実行してみてエラー表示から足りないdllを確認した。以下はとりあえずパッケージダウンロードを試してエラーになったものだけ。これらのライブラリがあれば nuget からライブラリのダウンロードはできるようになる。

  • System.Data.dll
  • System.IO.Compression.FileSystem.dll
  • System.Net.Http.dll
  • System.Runtime.Serialization.dll
  • System.Xml.Linq.dll

必要になったmonoプロジェクトの情報

鍵IDとパッケージリポジトリURL
https://www.mono-project.com/download/stable/#download-lin-debian
パッケージリポジトリの追加のしかた
https://github.com/mono/docker/blob/1d31220a290b2b4d19654a8cdb4ba13888e29717/6.4.0.198/slim/Dockerfile
dllとパッケージ名の対応
https://github.com/mono/linux-packaging-mono/blob/master/debian/control

Dockerfileのベストプラクティ

docs.docker.jp

apt update, install, clean を同じ RUN で実行する。

RUN apt-get update \
     && apt-get install ... \
     ...
     && apt-get clean \
     && rm -rf /var/lib/apt/lists/*

vue-language-serverをvim-lspから使う設定をした

Vue Language Server

  • Vue Language Serverはnpmのパッケージvue-language-serverとして公開されている
    • vlsコマンドとして提供される
  • Vue Language ServerはLanguage Server Protocolのサーバー実装
    • vim-lspをクライアントとしてvimから利用することができる
  • Vue Language ServerはVeturが使用する言語サーバー

Vetur - Visual Studio Marketplace

vim-lspにvue-language-serverを登録する

let s:vls_exe=expand('~/node_modules/.bin/vls')
  
if executable(s:vls_exe)
    au User lsp_setup call lsp#register_server({
        \ 'name': 'vue-language-server',
        \ 'cmd': {server_info->[s:vls_exe]},
        \ 'whitelist': ['vue'],
        \ 'initialization_options': { 'config': {
        \     'html': {}, 'vetur': {'validation': {}, 'completion': {'scaffoldSnippetSources': {}}}
        \     }}
        \ })
else
    echohl ErrorMsg
    echom '`vue-language-server` is not installed.'
    echohl
endif

configが無いと言語サーバーで Cannot read property 'ScaffoldSnippetSources' of undefined などのエラーが発生する

上記のconfigでいくつかの機能を無効にしてるっぽいけど具体的に何するときの何の機能かなのかは確認していない。とりあえずエラーなく起動させるまでやった。

参考にした Vim8でvim-lspとasyncomplete関連でvue-language-serverを使う(細かいオプションは省略) · GitHub

Google Cloud ShellでClangのビルドをしようとしたけど時間がかかりそうだからやめた

2019年4月29日の時点で、google cloud shellにはclang-8がインストール済みだった。 知らずにソースコードからビルドしようとしたけどものすごく時間がかかりそうだったから断念した。 インストール済みだけどパスは通ってない。 export PATH=/usr/lib/llvm-8/bin:$PATHした。

$ sudo apt update
$ sudo apt full-upgrade
$ sudo apt install cmake

$ git clone --depth 1 -b llvmorg-7.1.0 --single-branch https://github.com/llvm/llvm-project.git
$ cd llvm-project
$ mkdir build
$ cd build

$ cmake ^
-G "Unix Makefiles" ^
-DLLVM_ENABLE_PROJECTS=clang ^
-DLLVM_TARGETS_TO_BUILD=x86 ^
-DCMAKE_BUILD_TYPE=Release ^
-DCMAKE_INSTALL_PREFIX "インストールしたいpath"

$ make

ビルドしたいだけだから、git cloneには、depth 1 -b タグ --single-branchのオプションをつけて必要な分だけコピーした。

JavaScriptのフォーマッターPrettierのVimプラグインをインストールした

  • vim-prettierは、デフォルトの設定ではprettierのデフォルトルールとは違う整形ルールを持つ。
  • vim-prettierは、デフォルトの設定では.prettierrcがあればその設定を優先する。

prettier

prettier.io

prettierのインストール

プロジェクトローカルにprettierをインストールする。

npm init
npm install --save-dev prettier

使い方

npx prettier --write index.js
  • --writeはファイルを上書きする
  • --checkはdiffではなく、整形済みかどうかのみを出力する

vim-prettier

github.com

インストール

~/.vim/pack/<pkgname>/start/にgit cloneする。 vimrcに何も指定しなくても:Prettierコマンドを実行すれば使える。

  • g:prettier#exec_cmd_path

    • 指定しなくても、パッケージルートのnode_modules/.bin/prettierが使用された
    • コマンドを探す順は、READMEに書いてあった
    • 現在のパスは :PretierCliPathで確認できる
  • g:prettier#exec_cmd_async default:0

    • デフォルトでは非同期実行ではない
  • <Leader>p:Prettierコマンドがマップされている

Prettierの整形オプション

CLIでオプションなしで実行した場合と、vim-prettierでオプションを既定値で実行した場合とで結果が違う。 引用符の一重と二重とか他にも。 READMEに書いてあった、意図的にcliのdefaultとは違うオプション指定にしてあるそうな。

github.com

prettierrc

.prettierrcを置けば、vim-prettierもそれを読む。

  • g:prettier#config#config_precedence default: prefer-file
    • cli-override
      • 設定ファイルよりもcliフラグが優先される
    • file-override
      • cliフラグが設定ファイルとマージされる
    • prefer-file
      • 設定ファイルがあったらcliフラグは無視される
    • たぶんここでいうcliフラグは、vim-prettierがcliをコールするときに設定するg:prettier#configの各設定値のこと

{}だけを書いた.prettierrcをプロジェクトルートに置けば、prettier#config#config_precedence = prefer-fileのときにvim-prettierの整形ルールがデフォルトのCLIの整形ルールと同一になる。

タイトルが付けられるならブログに書く

自然とタイトルが思い浮んでいないのならtwitterに書く。ブログに短かいエントリーを書いてもいい。題名というかキャッチフレーズ的なものをひらめいて、それから何かを思うことがよくある。ツイートにはタイトルが付けられない。