Linux Desktop でも VS Code 使う

これまで Linux はもっぱら SSH で使ってたのですが、ここにきて Desktop も使うようになってきました。Kubernetes にデプロイしたアプリの動作確認を VM の localhost でするためです。

当然コードを書くのは VS Code の生産性が圧倒的に高いのでインストールしました。

会社ではプロキシサーバ配下で利用するのですが、拡張をインストールしようとすると settings.json で proxy 設定していても market place から取得できません。ぐぐったところ、起動用ファイルの設定で起動時オプション --proxy-server を追加すればよいようです。

GNOME では VS Code は「お気に入り」に自動追加され /usr/share/applications/code.desktop が起動用のファイルのようです。このファイルを以下のように編集したところ、無事拡張をインストールできました。

[Desktop Entry]
Name=Visual Studio Code
Comment=Code Editing. Redefined.
GenericName=Text Editor
Exec=/usr/share/code/code --no-sandbox --unity-launch --proxy-server=proxy.server.host:8080 %F
Icon=com.visualstudio.code
Type=Application

フォントは DejaVu Sans Mono を入れるとわりと見やすくなりました。

f:id:kondoumh:20200217222527p:plain

コードを書いている分には Windows や macOS と同等に動作している印象です。

VirtualBox 6.1 で Intel CPU の Nested Virtualization が解除された

Nested Virtualization は仮想マシンからホストマシンの CPU の仮想化機能を利用できる機能です。

VirtualBox では AMD CPU の Nested Virtualization が 6.0.6 でリリースされました。そして 6.1.0 で Intel CPU でも Nested Virtualization が利用できるようになりました。

Changelog – Oracle VM VirtualBox

リリースノートには、

starting with 5th generation Core i, codename Broadwell

とあり、僕の MacBook Pro Early 2015 は ギリギリ第5世代ですので使えるはずです。

現バージョンでは仮想マシン名を指定して個別に有効化する必要があります。

2.34. Nested Virtualization

'Ubuntu 18' という仮想マシンに対して Nested Virtualization を有効化するには以下を実行します。

$ VBoxManage modifyvm 'Ubuntu 18' --nested-hw-virt on

これで、有効化されました。

f:id:kondoumh:20200211235159p:plain

仮想マシンを起動して CPU がハードウェア仮想化をサポートしているか確認してみます。

KVM/Installation - Community Help Wiki

$ egrep -c '(vmx|svm)' /proc/cpuinfo
1

この数値が1以上ならサポートされているので OK です。KVM2 をインストールしてみます。

$ sudo apt install -y qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils

インストールが終わって KVM acceleration が利用可能になったかチェック。

$ kvm-ok 
INFO: /dev/kvm exists
KVM acceleration can be used

大丈夫みたいです。

/dev/kvm へのアクセス権をログインユーザーに付与します。

$ sudo chown <username> /dev/kvm

libvirt でエラーがないことを確認。

$ virt-host-validate

virt-host-validate
  QEMU: Checking for hardware virtualization                                 : PASS
    :
  QEMU: Checking for cgroup 'blkio' controller mount-point                   : PASS
  QEMU: Checking for device assignment IOMMU support                         : WARN (No ACPI DMAR table found, IOMMU either disabled in BIOS or not supported by this hardware platform)
   LXC: Checking for Linux >= 2.6.26                                         : PASS
    :
   LXC: Checking if device /sys/fs/fuse/connections exists                   : PASS

OK でした。

/etc/libvirt/libvirtd.conf に以下の設定を追加

unix_sock_group = "libvirtd"
unix_sock_ro_perms = "0770"
unix_sock_rw_perms = "0770"

いったんリブートしておきます。

KVM を使って Ubuntu の仮想マシンに CentOS 7 仮想マシンをインストールしてみます。

$ curl -LO http://ftp.riken.jp/Linux/centos/7.7.1908/isos/x86_64/CentOS-7-x86_64-DVD-1908.iso

$ sudo kvm -hda centos7.img -cdrom CentOS-7-x86_64-DVD-1908.iso -boot once=d -m 512

インストーラが起動。

f:id:kondoumh:20200212220124p:plain

インストーラの GUI が起動しました。

f:id:kondoumh:20200212221907p:plain

ソフトウェアインストール後の initramfs の初期化などにすごく時間がかかっていましたが、なんとかコンソールが起動しました。

f:id:kondoumh:20200213082002p:plain

ホストマシンが実機の場合は当たり前の光景ですが、これが仮想マシン内で実行されているのは中々凄いですね。

QEMU で仮想マシンが動くなら、Minikube で KVM も使えそうです。

以前 Minikube を macOS の HyperKit と Windows の Hyper-V で使ってみました。

blog.kondoumh.com

Linux 版の Minikube をインストールします。

Linux | minikube

$ curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube_1.7.2-0_amd64.deb \
 && sudo dpkg -i minikube_1.7.2-0_amd64.deb

vm-driver に kvm2 を指定して minikube を実行

f:id:kondoumh:20200212004452p:plain

CPU が振り切ったまま、マウスカーソルすら表示されなくなってしまいました。

ということで、マシンパワーが足りないのか VirturlBox 側の最適化が足りないのか、僕の環境では実用的な速度では動きませんでした。もう少し熟成を待つ方がよさそうです。

GitHub Actions で再利用可能な Action を作る

GitHub Actions では、よく使う処理を Action として切り出して再利用できます。Marketplace にはすでに多くの Action が登録されています。

GitHub Marketplace · Actions to improve your workflow · GitHub

Action には Docker Container Action と JavaScript Action という2種類の実装方法があります。

Docker Container Action

help.github.com

GitHub Actions が実行される Runner にインストールされていないソフトウェアを Docker コンテナに入れて ENTRYPOINT で実行する用途がメインです。kubectl などをワンショットで実行したい場合です。Docker なので実装する言語を選ばないというのも特徴ですが、シェルスクリプトを使っているケースが多い印象です。

Terraform の公式 Action がこの形式です。

github.com

init / validate / plan と Terraform のサブコマンドを実行するたびに裏では コンテナがビルドされ docker run で実行されます。実行コストは高いけど、GitHub Actions の Runner は Azure の高可用性サーバで実行されてるのでまあいいかという感じ。実装コストは低いので CI で必要な部品を手軽に作って共有できます。

Dockerfile の他に Docker Hub のパブリックなイメージを指定して毎回ビルドが走らないようにすることもできます。GitHub Package Registry のパブリックなイメージは現在のところなぜか利用できません*1

JavaScript Action

help.github.com

JavaScript Action は GitHub 提供の NPM パッケージを使って作る Action です。ワンショットの実行だけでなく環境構築してマルチラインで処理を書きたい場合などに適しています。コンテナではなく Runner の環境に変更を加えることになります。

ソフトウェアのダウンロード、インストール、コマンド実行などをすべて JavaScript (もしくは TypeScript) で書きます。

const core = require("@actions/core");
const tc = require("@actions/tool-cache");
const exec = require("@actions/exec");
const io = require("@actions/io");
const path = require("path");

async function download(url) {
  const downloadPath = await tc.downloadTool(url);
  return downloadPath;
}

async function extract(downloadPath) {
  const folder = await tc.extractTar(downloadPath);
  return folder;
}

async function install(downloadPath, filename) {
  const binPath = "/home/runner/bin";
  await io.mkdirP(binPath);
  await exec.exec("chmod", ["+x", downloadPath]);
  await io.mv(downloadPath, path.join(binPath, filename));
  core.addPath(binPath);
}

Actions のライブラリを使うことで Runner の環境がクリーンナップされているのではないかと思います。

help.github.com

JavaScript Action で helmfile と関連のソフトウェアをインストールする Action 作ってみました。まだ Marketplace には登録していませんが。

github.com

ちなみにこの Organization は僕の所属会社のです。

*1:認証エラーになってしまいます。

野良 Scrapbox アプリ - 本文を Markdown 形式でクリップボードにコピー

Scrapbox はシンプルな記法で WYSIWYG を実現した稀有なサービスです。プレビューなしにサクサク書けるのです。

Scrapbox で作成した文書を Wiki などに転記するために本文を Markdown 形式に変換してクリップボードにコピーする機能を追加しました。

見出し

Scrapbox には見出しという概念がなく、文字サイズの修飾を使ってます。文字サイズを決め打ちで Markdown の見出しレベルにマッピングするようにしました。

箇条書き

Scrapbox はインデントが箇条書きになるので、Markdown への変換は容易です。

リンク

Scrapbox のリンクは Markdown より簡易な記法になっていますのでこれも変換します。

コードブロック

Scrapbox のコードブロックは code:index.html のような形式なので、ファイル名を出力してから拡張子をそのままコードブロックの開始部分に追加しています。拡張子ではコードハイライトされない言語もあるかもしれません。

Scrapbox の表はタブ区切りになっているので、| で join しています。

イメージ

Gyazo の 画像は一律 png として変換するようにしてます。HTML を scraping すればフォーマットが分かりますがそこまではしてません。

Scrapbox の記法がシンプルなため、正規表現と少しのコードで実装できました。他にも数式などの記法もありますが変換はしてません。

scrapbox.io

以下は上記のページの変換例です。


Sandbox page

Heading1

Heading2

Heading3

Heading4

goroutines.go

 package main
 
 import (
  "fmt"
  "time"
 )
 
 func say(s string) {
  for i := 0; i < 5; i++ {
      time.Sleep(100 * time.Millisecond)
      fmt.Println(s)
  }
 }
 
 func main() {
  go say("world")
  say("hello")
 }

metasyntactic variables

lang 1st 2nd 3rd
us foo bar baz
jp hoge huga piyo
python spam ham eggs


Release v1.4.0 · kondoumh/sbe · GitHub

GitHub Actions の run ではパイプの終端の結果がジョブのステータスになる

GitHub Actions でテスト実行を tee で標準出力しつつファイルに出力するようにしました。

jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      - name: Test & report
        run: |
          go test . -v 2>&1 | tee result.txt
           :

出力されたファイルをレポーティング用のツールで加工してテスト結果レポートなどの成果物を作成したいためです。

しかし、テストが失敗してもワークフローが success() になってしまいます。

        run: |
          go test . -v 2>&1; test $? -ne 0 && exit 1 | tee result.txt

とかやるとテスト失敗したらfailure() にはなりますが、意図した内容がファイルに出力されません。

次のようにリダイレクトではちゃんとエラーになってくれます。

        run: |
          go test . -v 2>&1 > result.txt
           :

GitHub Actions の run ではコマンドパイプの途中の処理でエラーになっても終端の処理が成功しているとジョブステータスも success() になってしまうようです。ワンライナーで色々やりたい場合、ちょっと不便ですね。

テストの失敗はジョブのステータスとして検出したいのでテスト実行のみの step とテスト&レポート作成の step に分割しました。

jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      - name: Test
        run: |
          go test . -v

      - name: Test & report
        run: |
          go test . -v 2>&1 | tee result.txt
          :

この場合 test が失敗するとワークフロー自体は終了するので後続のテスト&レポート作成 step は実行されません。失敗成功にかかわらず後続の step を実行したい場合は、実行条件に always() を指定することで実行を強制可能です。

jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      - name: Test
        run: |
          go test . -v

      - name: Test & report
        if: always()
        run: |
          go test | tee result.txt
          :

後続の step が成功しても、それ以前の step がエラーになっていればジョブ自体は failure() になります。

help.github.com

テストを2回実行するコストが許容できない場合、テスト結果をファイルにリダイレクトして後続の step でログ出力するというやり方も考えられます。

jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      - name: Test & report
        run: |
          go test . -v 2>&1 > result.txt
          :

      - name: Print test result
        if: always()
        run: cat result.txt

この方法だとエラーが発生してもログ出力の step は成功するためログがどこに出ているのかわかりづらいという問題はあります。

f:id:kondoumh:20200119163222p:plain

GitHub Actions & kind (Kubernetes IN Docker) で Matrix build の CI を構築

CI で Kubernetes を使いたい場合、自前の Kubernetes 環境か GKE や EKS を利用して常時クラスターを使えるようにしておく方法があります。

しかし、ワーカーのノード数を色々変えてテストしたい、Kubernetes のバージョンを色々変えてテストしたい、常設のクラスターを準備するのがコスト的に厳しい・・などの場合、Docker 環境さえあれば揮発的に素早くクラスターを構築して終了後に破棄できる kind (Kubernetes in Docker) が有効です。

blog.kondoumh.com

GitHub Actions の Marketplace でも kind を使う Actions が公開されていました。

github.com

workflow の steps で以下のように指定するだけで kind でクラスターを構築できます。

    steps:
    :
    - uses: engineerd/setup-kind@v0.2.0
    :

kind の Config ファイルも width: に指定できます。

    - uses: engineerd/setup-kind@v0.2.0
      with:
        config: "k8s/kind.yml"

Kubernetes のバージョンを指定したいときは、kindest/node イメージのバージョンを指定すれば OK です。

    - uses: engineerd/setup-kind@v0.2.0
      with:
        image: kindest/node:v1.14.9

kind を手動起動する場合 Config ファイル内で kubeadmConfigPatches を使って kubeadm のオプションを与えるのですが、この Action では workflow 内で指定可能です。

複数バージョンの Kubernetes を使う Matrix build のサンプルを作ってみました。kindest/node のタグを matrix にしています。

name: "Create cluster using KinD"
on:
 push:
  paths:
  - k8s/**
  - .github/workflows/it_k8s.yml

jobs:
  kind:
    strategy:
      matrix:
        k8s: [1.14.9, 1.15.7]
  
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@master
    - uses: engineerd/setup-kind@v0.2.0
      with:
        config: "k8s/kind.yml"
        image: kindest/node:v${{ matrix.k8s }}
    - name: Testing
      run: |
        kubectl version
        kubectl cluster-info
        kubectl get node -o wide
        kubectl get pods -n kube-system
        kubectl apply -f k8s/nginx_deploy.yml
        kubectl describe deployment nginx-deployment

テストでは kubectl で nginx のマニフェストを apply して deployment を describe する処理を書いています (本来はデプロイしたアプリケーションのエンドポイントに対して E2E のテストを実行します)。

クラスターはデフォルトでシングルノード構成で起動されるので、複数ワーカー構成にしたい場合 Config ファイルで指定します。今回は、master (1) / worker (2) で構築しました。

# three node (two workers) cluster config
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4

nodes:
- role: control-plane
- role: worker
- role: worker

実行すると Kubernetes バージョン毎の結果が表示されます。

f:id:kondoumh:20200114231329p:plain

kind と Matrix build は相性がいいですね。

2019 ふりかえり

Job

引き続きプロダクト開発プロジェクト。1年以上在任してます。Kubernetes を中心とした開発環境・実行環境・CI/CD パイプラインの構築をやって IaC の良さも難しさも実感しています。

別のサービス開発プロジェクトにも少し入りました。こちらはコテコテの Java アプリでコード改善が主体です。

共に来年も続いていきそうです。

Private Project

GitHub の草は生やし続けてます。

野良 Scrapbox アプリは自分が一番のユーザということもあり、かなり更新して Electron にも馴染みました。

Vue は最近触ってませんが、v3 が出たら見ようかなと。

CI/CD ツールも色々と試しました。

11月にリリースされた GitHub Actions を public beta から使って気に入っています。野良 Scrapbox アプリの Windows / macOS のインストーラ配布もできました。

ホームページを Hugo に移行し GitHub Actions でジェネレートから公開まで自動化しました。

Hugo もですが Cloud Native なソフトウェアの多くが Go で書かれており、仕事で Go の開発環境・CI 整備をやっているので、個人的にもツール作成に使い始めました。久々に触るとかなり進化してました。Go Modules はかなりイケてる気がします。

今後 Go や d3.js などで可視化ツールを開発しようと思ってます。

Writing

ブログは週1以上ぐらいのペースで更新してました。

Scrapbox はすっかり会社のインフラになりました。僕もよく書いてます。個人プロジェクトも集約しました。

Software / Services

Netlify

PWA の配布やちょっとしたバッチ処理に使っています。

GCP

VM インスタンスをよく使ってます。GKE も使うようになりました。

AWS

仕事で EKS 中心に使ってます。個人アカウントはあまり使ってませんが、会社でアカウントもらったので来年から色々使うと思います。

DigitalOcean

Droplets をスポット利用してます。Kubernetes もローンチしたので使うかも。

VS Code

あらゆる開発環境が VS Code で構築できるようになってます。

Gitpod

iPad でも使える VS Code ベースの Web IDE。VS Code Online も出たし Eclipse Che や CodeSandbox も VS Code ベースだし・・と、Web IDE 界も VS Code が席巻してます。

Emacs

ターミナル作業も多いので設定や利用パッケージを見直しています。

Kibela

ドキュメント下書き・ToDo 管理・コードスニペット管理に使っています。PWA であらゆる場所で閲覧・編集できて便利。ただ、カーソルの挙動がおかしかったり投稿がうまくできなかったりする時があり、改善が望まれます。

Kibela (キベラ) - 個人の発信を組織の力にする情報共有ツール

draw.io

AWS アイコンも充実してシステム構成描くのに重宝します。Electron アプリになりました。

Flowchart Maker & Online Diagram Software

Ingress

Resurgence メダルもらいました。

Gadgets

中華ワイヤレスイヤホンとか Qi 充電器を買ったぐらい。

scrapbox.io

scrapbox.io

奥さん用に iPad Pro 書いました。

scrapbox.io

自分はまだ iPad Air 2 です。iPadOS でかなり使い勝手がよくなり、出先での作業はだいたい賄えてます。もう1世代ぐらい様子見かな。

MacBook Pro 13 Early 2015 も使い続けてます。そろそろ 6コアぐらいのマシンが欲しいところ。持ち歩かないので Mac mini とかでもいいかも。

まとめ

仕事も個人プロジェクトも1年前よりさらに Cloud Native 化が進んでいる気がします。コンピューティングもそれに合わせて変わっていくのでしょう。