ソースコードから理解する技術-UnderSourceCode

手を動かす(プログラムを組む)ことで技術を理解するブログ

Visual Studio CodeのRemote DevelopmentでWSL内のGolangを書いてみる

ちょっと前(だいぶか?)Visual Studio Codeでリモートで接続して編集できる「Remote Development」が登場して気になっていました。
Visual Studio Code Remote Development

登場したときは正規のVisual Studio Codeではなく、プレビュー版?のVisual Studio Code Insidersからしか使えなかったのですが
今回は正規のVisual Studio Codeで使ってみました。

以下、簡単ですがその手順を書きたいと思います。

前提条件

Windows上にWSL(Windows Subsystem for Linux)を入れておいてください。
今回はWSL上にGolangの開発環境を用意し、WSL上のGolangのプロジェクトが編集できるかを試してみました。

手順について

1. Visual Studio CodeにRemote Developmentをインストール
コマンドパレットのInstall Extentionsに「Remote Development」と入力すると検索結果として表示されるので、インストールします。

2. Visual Studio CodeをRemoteで起動
既にWSL上にはGolangのプロジェクトが存在するものとします。
ややこしいのですが、$ bashでWSLに切り替え、WSL上ででプロジェクト直下に移動して「$ code .」を実行します。

$ code .
Installing VS Code Server xxxxxxxxxxxxxxxx
Downloading: 100%
Unpacking: 100%

実行すると上のようになり、Visual Studio Codeが起動します。
Visual Studio Codeのタイトルバーに[WSL]と表示され、[view]-[terminal]でターミナルを軌道するとWSLに切り替わっていれば成功です。

3. Go Extentions を導入
Setup Go Development Environment with VS Code and WSL on Windows
こちらの記事を参考に、Extentisonsとして「Go Extensions」をインストールして設定します。
私の場合は既にインストール済だったので、「Go Extensions」の「Install on WSL」を行い、WSL用のもインストールしました。

4. Go toolsのインストール
Go tools that the Go extension depends on · microsoft/vscode-go Wiki · GitHub
こちらにあるコマンドをコピーして、WSLのターミナルでgo getを実行して必要なものをインストールします。

5. settings.jsonの設定
Setup Go Development Environment with VS Code and WSL on Windows
こちらにあるように、Visual Studio Codeの[file]-[preferences]-[settings]を押下してRemote[WSL]タブを選択します。
[Extentions]-[Go configuration]よりsettings.jsonを開き、先の参考サイトのような定義を追加します。

ただ私の場合は

  • "terminal.integrated.shell.linux"は設定しない
  • "go.formatTool"には"goimports"を指定する
  • "go.gopath"、"go.goroot"は適切なものを指定する

という点を変えました。

"goimports"についてはapt-get等でWSL側にインストールする必要があります。


以上でWSLのGolangVisual Studio Codeで開発できるようになりました。
WSL上のGolangのコードを編集してみましたが、ローカルで開発するときにようにファイル保存時のフォーマット・自動importや構文エラーの表示もできているようです。

Terraformを初めて触ってみた

タイトルにあるようにTerraformに初めて触ってみました。
やったこととしては、

です。

もう何番煎じの記事になるのか分からないですが、自分への備忘録として残しておきます。

インストール

インストールはWindows Subsystem for LinuxUbuntuで行いました。Linuxbrewを入れてあるので、Macと同様のコマンドになるかと思います。

$ brew update
$ brew install terraform

EC2を立てる~削除

既にAWS CLIAWSにアクセスできるよう、~/.aws/credentialsは定義済でした。なのでTerraformの定義ファイルを書き、実行しただけです。
まずTerraformの定義ファイルです。

example.tf

provider "aws" {
  region     = "ap-northeast-1"
}
resource "aws_instance" "example" {
  count         = 1
  ami           = "ami-084040f99a74ce8c3"
  instance_type = "t2.micro"

  tags = {
    Name = "${format("example%02d", count.index + 1)}"
  }
}

ファイル名は何でもいいと思いますが、.tfという拡張子とします。内容としては

  • リージョンにはap-northeast-1、つまり東京を使う
  • exampleという名前で作る
  • 数は一つ
  • AMIはAmazon LinuxのAMI IDを指定
  • インスタンスタイプはt2.micro
  • タグをフォーマットを指定して設定

をしています。

後はexample.tfを保存したフォルダで以下のコマンドを実行します。

$ terraform init      # init 初回だけ?
$ terraform plan    # plan 実行前に構築されるオブジェクトを確認できる
$ terraform apply  # apply 構築するコマンド

「apply」を行うと「Do you want to perform these actions?」と聞かれるので「yes」と入力します。
構築されたら、applyの実行結果とAWSのマネージメントコンソールとで結果を見比べてみましょう。また以下の「show」でも構築した結果を見ることができます。

$ terraform show

最後に構築したものを消して終了します。

$ terraform destroy

以前ちょくちょく使ったServerless Frameworkもそうですが、Terraformのような構成管理ツールはコマンド一発で作った環境を削除できることが、個人的には気に入っています。

survey を使ってインタラクティブなプロンプトを作ってみた

GitHub - AlecAivazis/survey: A golang library for building interactive prompts with full support for windows and posix terminals.

タイトルにあるように、surveyを使ってインタラクティブなプロンプトを作ってみました。
どんなことが出来るかやイメージは、先頭に載せたsurveyのURLのREADMEを見れば一発で分かるかと思いますw

使い方もREADMEに書かれているのですが、雰囲気を掴むために自分でも実装してみました。

以下、今回作ったものの簡単な解説になります。
作ったものの想定はシステムのインストーラのプロンプトとなり、以下の項目を入力 or 選択させます。
(見やすくするため各項目を一行ずつ開けてあります)

? What is this system name? sample system

? Input system detail. [Enter 2 empty lines to finish]
Sample
System
Installer

? Choose your OS.:  [Use arrows to move, space to select, type to filter]
> Windows
  Linux
  Mac
  Unix
  Other

? Select install functions:  [Use arrows to move, space to select, type to filter]
  [x]  Web Server
  [ ]  Application Server
  [x]  Slack Notification
  [ ]  Database Backup

? Please type your system password.: ********

? Would you like to insatll now?: (y/N) y

上から順に書くと

  • システム名 ・・・ 文字列
  • システム詳細 ・・・ システムの詳細。複数行文字列
  • OSの種類 ・・・ WindowsLinuxMacなどから一つを選択
  • インストール機能 ・・・ Web Server、Application Serverなどから複数選択
  • パスワード ・・・ パスワード入力
  • 確認 ・・・ y/Nでインストールするかの確認。

です。

最後まで入力すると、JSON形式で今回はターミナルに入力した内容を出力してみました。
よくあるターミナルからの入力は、大体これで作れるのではないかと思います。

今回私が作ったサンプルは以下に置いてあります。
先に書いたプロンプトの実装が知りたい場合は参考にしてみてください。
https://github.com/SrcHndWng/go-survey-sample

「Goならわかるシステムプログラミング」を読んだ

「Goならわかるシステムプログラミング」の一連の記事をゴールデンウィーク中に読んでました。
ASCII.jp:Goならわかるシステムプログラミング

単純にコーディングしているだけでは意識することが少ない、低レイヤーの話が分かりやすく書かれており、必要になった時に再読したいと思います。

以下、読んでだ時のメモを纏めた(纏まってのか?)、チラシの裏書きレベルのメモとなりますw
再読するときなど、読み直す箇所のあたりを付けるのに使おうかな、と。。。

第1回

デバッガなどの準備。

第2回・3回・4回

io.Writer、io.Readerについて。

https://jibun.atmarkit.co.jp/lskill01/rensai/fulinux/03/01.html

こちらの

Linuxには「ファイルシステム」「プロセス」「ストリーム」という3つの概念

を念頭に読み進めた。

プロセスはGolangで書くプログラムそのものだとすると、ファイルシステムとストリームを取り扱うのが
1~3回で扱っているio.Writer、io.Readerインターフェースとなるか。

なお「ファイル」は普段使うテキストファイルに留まらず、入出力先の全て(標準入力・出力や画面など)を指す。
OSレベルではファイルディスクリプタが指す先であり

POSIX系OSでは、可能な限りさまざまなものが「ファイル」として抽象化されて

いる。(https://ascii.jp/elem/000/001/243/1243667/ より)

第5回

システムコールについて。

第6・7・8・9回

ソケット通信まわりについて。

ソケット通信でもファイルシステムとストリームを取り扱うio.Writer・io.Readerを経由して読み書きしている。
Golangを案件で使っている会社であれば、新人研修でWebサーバを作り、ブラウザやcrulでアクセスしてレスポンスを取得する所をやると理解が深まるかも・・・、など思った。

第10・11・12回

ファイルシステムの様々な扱い方について
fsnotifyとgoルーティンを使ったファイルの変更を監視する例、ファイルをロックする例、など。
同期・非同期・ブロッキング・ノンブロッキングについての分かりやすい説明。

第13・14・15回

プロセス、シグナルについて。
Graceful Restartなどアプリでシグナルを扱う例など。

第16・17・18回

並列処理、「スレッドとgoroutineの違い」、「並列処理のパターン」について。
syncパッケージを使った、様々なgoroutineの制御の具体例。
並列処理を実装する前に再読したい。

第19回

メモリ管理について。

第20回

コンテナについて。
仮想化、コンテナの違い。
Golangでコンテナを実装する例。

「UNIXという考え方」を読んだ

平成最後の日、UNIXという考え方 を読みました。
shop.ohmsha.co.jp

著者自身が書いているように分かりやすい口語体で書かれているので、内容が気になる方は本書を読むことをお勧めします。

以下、本書を読んで感銘を受けたところについて備忘録として纏めておきます。なお、鍵括弧で囲っているのは本書内の文を引用しているものです。

  • 第3章 楽しみと実益をかねた早めの試作
    • unix開発者の仕事の進め方について
      • 「1. 短い機能仕様書を書く」
      • 「2. ソフトウェアを書く」
      • 「3. テストして書き直す。満足できるまで、これを繰り返す」
      • 「4. 詳細なドキュメントを(必要なら)書く」
  • 第5章 これこそ梃子の効果!
  • 第6章 対話的プログラムの危険性
    • 「すべてのプログラムはフィルタである」
  • 第8章 一つのことをうまくやろう
    • 章のタイトルそのもの
    • MHというメーラーがUI層・アプリケーション層・小プログラム集合層の3階層になっていること
      • 3層構造は、Webなどで今でも使われている
    • 「開発者は詳細仕様書の作成に何週間も何ヵ月も費やす無駄をやめ、計画の目指すおおよその方向を文章にまとめたら、さっさと開発に取りかかった方がよい。」
      • この前後のP130からの「8.1 UNIXの考え方:総括」。

Serverless Frameworkを使ってLambdaでPDFを出力するサンプルを作ってみた

久しぶりにAWS と Serverless Frameworkを使い、LambdaにてDynamoDBからデータを取得し、PDFをS3に出力するサンプルを作ってみました。

CloudWatchなどで定期的にLambdaを起動することを考えると、割と実案件ではありがちな要件かと思われます。

今回作ったサンプルは以下になります。
GitHub - SrcHndWng/go-serverless-dynamo-report

割とサクッと作れるかと思ったのですが、意外と色々調べながら作ることになったので、今回調べた点をメモとして載せておきます。

サンプルを作るのに調べたこと

  • DynamoDB Localの使い方
  • go-assets-builderを使ってテキストファイルをバイナリに組み込む方法
  • gopdfを使ってのPDF作成

以下、それぞれについて書いていきます。

DynamoDB Localの使い方

serverless-dynamodb-localをインストールして「$ sls dynamodb start」でDynamoDB Localを起動すると
Unable to start DynamoDB Local process!
というエラーとなりました。

以下のURLよりDynamoDB Localをダウンロードし、解凍したフォルダごと ./node_modules/dynamodb-localhost/dynamodb/bin に入れることで解決しました。
https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html

go-assets-builderを使ってテキストファイルをバイナリに組み込む方法

GitHub - jessevdk/go-assets-builder: Simple assets builder program for go-assets
こちらをgo get で取得します。

今回はPDFを作成するためのフォントのフォーマットファイルである「times.ttf」ファイルをgo-assets-builderを使ってバイナリに組み込みます。
バイナリに組み込む理由は、Lambdaにシングルバイナリとしてデプロイしたいためです。

READMEにも書いたのですが、「times.ttf」ファイルを以下のサイトより取得するなどして用意し
./report/assets/times.ttf に配置します。
https://github.com/oneplus1000/gopdfsample/tree/master/ttf

その上で以下のコマンドを実行すると、「assets.go」というファイル名でtimes.ttfがビルド可能な.go ファイルに変換されます。

go-assets-builder -p main -o assets.go assets/

今回はややこしいですが、バイナリに組み込んだtimes.ttfをアプリ内で読み込み、ファイルとして復元してLambdaの実行環境内の/tmp/times.ttfに出力しています。

これはtimes.ttfをフォントのフォーマットファイルとして、PDF出力のためのライブラリに渡したいためです。
実装についてはmain.goを参照してください。

assetFile, err := Assets.Open("/assets/times.ttf")

でバイナリに組み込まれたtimes.ttfを開いています。

gopdfを使ってのPDF作成

GitHub - signintech/gopdf: A simple library for generating PDF written in Go lang
gopdfを使い、PDFファイルを出力しています。すごく簡単にですが、縦線・横線とDynamoDBから取得したデータを出力してみました。

gopdfを使った理由は、すべてGolangで書かれているため、ビルドしたバイナリ単体でPDFを出力できるためです。

こちらについては今回のソースよりも、以下のサンプルソースの方が実装方法は分かりやすいかと思いますw
GitHub - oneplus1000/gopdfsample: example of gopdf (https://github.com/signintech/gopdf)

Go Moduleでローカルパッケージを作成する

Using Go Modules - The Go Blog

Go Moduleについての上記の公式サイトではhello.go、それのテストであるhello_test.goを
GOPATHの外に実装する方法について書いてあります。

ですが実際にプログラムを作るときには、ローカルに幾つかのパッケージを作ることが多いかと思います。
例えば以下のような構成です。

.
├── hello/
│   ├── hello.go
│   └── hello_test.go
└── main.go

上記の構成で

  • hello.go、hello_test.goは公式サイトのソースのまま
  • main.goからはhello.goのメソッドを呼び出す
  • 「$ go mod init example.com/hello_main3」ようなgo mod init はmain.goと同階層で行う

をしたところ、ビルド時に以下のようなエラーとなりました。

build example.com/hello_main3: cannot find module for path ~

対応方法としては以下のサイトを参考にさせて頂きました。
https://pod.hatenablog.com/entry/2018/12/26/074944

結論を書けば、main.go内でhelloパッケージをimportする際に、相対パスではなく絶対パスで指定すればいいようです。
こんな感じになります。

import "example.com/hello_main3/hello"

このように書くことで、ビルドしての実行、helloパッケージ内でのテストの実行をすることができました。