emahiro/b.log

Drastically Repeat Yourself !!!!

Deno で 3rd party 製ライブラリをいれる

Overview

Deno で 3rd party のライブラリを import する方法についての備忘録です。

Install third party libraries

公式ドキュメントの https://deno.land/x に記載している手順になります。

https://deno.land/x/MODULE_NAME@BRANCH/SCRIPT.ts を import に追加します。
バージョンを指定したい場合には、https://deno.land/x/MODULE_NAME@vX.X.X/SCRIPT.tsv を付けます。(この辺もなんとなく Go のお作法っぽさがありますね。)

※ Deno は node のエコシステムから外れているので何か必要なライブラリがあるときはファイルにて直でバージョンと import したいライブラリ名を指定します。公式のライブラリですが同様の形式をとります。

Install oak

Deno でいい感じの web サーバーを書ける Router のライブラリを探していたら oak がヒットした( deno.land/x 配下にもあるし、スター数も多い)のでこれを入れてみます。

Deno の公式ドキュメントに記載されてる方法で oak を import します。

import { Application } from "https://deno.land/x/oak@v5.3.1/mod.ts";

const port:number = 8080;
const app = new Application()

app.use((ctx) => {
    ctx.response.body = "Hello oak app"
})
app.addEventListener("listen", ({ hostname, port}) => {
    console.log(`Start server on ${hostname}:${port}`);
  });
await app.listen({hostname: "127.0.0.1", port: port})
console.log("Shutdown server.")

これでアプリを起動してみると

$ deno run --allow-net --unstable main.ts
Download https://deno.land/x/oak@v5.3.1/mod.ts
Download https://deno.land/x/oak@v5.3.1/application.ts
Download https://deno.land/x/oak@v5.3.1/context.ts
Download https://deno.land/x/oak@v5.3.1/helpers.ts
Download https://deno.land/x/oak@v5.3.1/cookies.ts
Download https://deno.land/x/oak@v5.3.1/httpError.ts
# ...

と言う感じで依存 module が DL -> コンパイルされてサーバーが起動します。

シュッとサーバー書くときには便利だなーと思いました。

1点不満があるとすると、エディタ上ではまだ DL していないモジュールの補完を聞かせることができないことかなと思います。まぁそれはそうだろう、って言う気もしてますが。

Operation CREATE USER failed for 'root'@'%' エラーが出て MySQL コンテナが起動に失敗する

FROM mysql:8.0.20

ENV MYSQL_USER root
ENV MYSQL_PASSWORD root
ENV MYSQL_ROOT_PASSWORD root
ENV MYSQL_DATABASE test
ENV MYSQL_HOST 127.0.0.1
ENV MYSQL_PORT 3306

と言う設定で MySQL のコンテナを起動したところ

$ docker run --name $ContainerName -it --rm -p 3306:3306 $ImageName
2020-06-14 14:26:53+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.20-1debian10 started.
2020-06-14 14:26:53+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
2020-06-14 14:26:53+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.20-1debian10 started.
2020-06-14 14:26:53+00:00 [Note] [Entrypoint]: Initializing database files
2020-06-14T14:26:53.845977Z 0 [Warning] [MY-011070] [Server] 'Disabling symbolic links using --skip-symbolic-links (or equivalent) is the default. Consider not using this option as it' is deprecated and will be removed in a future release.
2020-06-14T14:26:53.846034Z 0 [System] [MY-013169] [Server] /usr/sbin/mysqld (mysqld 8.0.20) initializing of server in progress as process 45
2020-06-14T14:26:53.851083Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
2020-06-14T14:26:54.201911Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.
2020-06-14T14:26:55.253759Z 6 [Warning] [MY-010453] [Server] root@localhost is created with an empty password ! Please consider switching off the --initialize-insecure option.
2020-06-14 14:26:57+00:00 [Note] [Entrypoint]: Database files initialized
2020-06-14 14:26:57+00:00 [Note] [Entrypoint]: Starting temporary server
mysqld will log errors to /var/lib/mysql/31fa027d7c28.err
mysqld is running as pid 94
2020-06-14 14:26:57+00:00 [Note] [Entrypoint]: Temporary server started.
Warning: Unable to load '/usr/share/zoneinfo/iso3166.tab' as time zone. Skipping it.
Warning: Unable to load '/usr/share/zoneinfo/leap-seconds.list' as time zone. Skipping it.
Warning: Unable to load '/usr/share/zoneinfo/zone.tab' as time zone. Skipping it.
Warning: Unable to load '/usr/share/zoneinfo/zone1970.tab' as time zone. Skipping it.
2020-06-14 14:27:00+00:00 [Note] [Entrypoint]: Creating user root
ERROR 1396 (HY000) at line 1: Operation CREATE USER failed for 'root'@'%'

と言うエラーが出てコンテナが起動できませんでした。

調べたら Dockerfile で MySQL の root ユーザー名を指定していたので MySQL のコンテナを起動する時に root ユーザーを作れないエラーでした。。。

According to this github issue, the problem is setting MYSQL_USER to root. It will fail to create the second user 'root'@'%' since it will already exist in the users table.

stackoverflow.com

MYSQL_USER に指定するユーザー名を root 以外にしたら無事起動できました。

Import maps in Deno

Summary

以下のマニュアルに書いてある内容。

deno.land

About import maps

deno ではファイル単位の import で依存関係を解決する。

しかし毎回 https://deno.land/std.../server.ts と書くのは面倒くさい。

そこで Import maps を使う。

main.ts と同じ階層に import_map.json を用意して import path をマッピングした設定を記載しておく。

{
   "imports": {
      "http/": "https://deno.land/std/http/"
   }
}

Import maps は deno のアプリを起動するときに importmap のオプション付きで実行することで使うことができるようになる。

$ deno run --allow-net --importmap=import_map.json --unstable main.ts

追記

import map を使っていると Docker build した時に相対 path が解決されないぽいということがわかりました。

docker build -t emahiro-server-app .
Sending build context to Docker daemon  6.144kB
Step 1/9 : FROM hayd/alpine-deno:1.0.2
 ---> 8f192534bc9d
Step 2/9 : EXPOSE 8080
 ---> Running in 040e0f46c354
Removing intermediate container 040e0f46c354
 ---> 93235a5af9db
Step 3/9 : WORKDIR /app
 ---> Running in 0ce7a5e2d58d
Removing intermediate container 0ce7a5e2d58d
 ---> 11c92994ff42
Step 4/9 : USER deno
 ---> Running in 53835c147244
Removing intermediate container 53835c147244
 ---> ab838d2a5833
Step 5/9 : COPY deps.ts .
 ---> a9cf8b680791
Step 6/9 : RUN deno cache deps.ts
 ---> Running in 0b7cb179006d
Compile file:///app/deps.ts
Removing intermediate container 0b7cb179006d
 ---> 623d7d2d90ee
Step 7/9 : COPY . .
 ---> 158e09d31676
Step 8/9 : RUN deno cache main.ts
 ---> Running in 9b0b179277d5
error: relative import path "std/http/server.ts" not prefixed with / or ./ or ../ Imported from "file:///app/main.ts"
The command '/bin/sh -c deno cache main.ts' returned a non-zero code: 1

import_map.json を コンテナ内に copy してもこの相対ぱすを解消できないっぽいです。。。 この先よくわかってない...

Deno on Cloud Run

Overview

Deno を CloudRun で動作させるまでをまとめました。

How to get started

インストール手順 に則って Deno で簡単な Web サーバーを起動します。

Install Deno

Mac では brew が使えるらしいのでとりあえず brew を使って deno を入れます。

$ brew install deno
$ deno --version
deno 1.0.2
v8 8.4.300
typescript 3.9.2

そしてドキュメントにも記載されてる通り簡単な動作確認は以下

$ deno run https://deno.land/std/examples/welcome.ts
Download https://deno.land/std/examples/welcome.ts
Warning Implicitly using master branch https://deno.land/std/examples/welcome.ts
Compile https://deno.land/std/examples/welcome.ts
Welcome to Deno 🦕

Sample web server

次に簡単な Web サーバーを立ち上げて見ます。

Deno で Web server を立ち上げるためには直で https://deno.land/std@0.53.0/http/server.ts を import して使うのが簡単のようです。import に https://deno.land/... のフォーマットで書いておけば、実行時に依存関係を取得できます。

お試しで動かしたいケースにおいては最適ですね。

Go みたいに自動的に取得してくれたりしないのかな。。。

import { serve } from "https://deno.land/std@0.53.0/http/server.ts";

const port = 8080;
const s = serve({ port: port });
console.log("Starting server port: ", port);
for await (const req of s) {
    req.respond({ body: "Hello World\n" });
}

このコードを書いた後 Deno を起動する。

$ deno run --allow-net ./main.ts
Download https://deno.land/std@0.53.0/http/server.ts
Download https://deno.land/std@0.53.0/encoding/utf8.ts
Download https://deno.land/std@0.53.0/io/bufio.ts
Download https://deno.land/std@0.53.0/testing/asserts.ts
Download https://deno.land/std@0.53.0/async/mod.ts
Download https://deno.land/std@0.53.0/http/_io.ts
Download https://deno.land/std@0.53.0/async/deferred.ts
Download https://deno.land/std@0.53.0/async/delay.ts
Download https://deno.land/std@0.53.0/async/mux_async_iterator.ts
Download https://deno.land/std@0.53.0/textproto/mod.ts
Download https://deno.land/std@0.53.0/http/http_status.ts
Download https://deno.land/std@0.53.0/io/util.ts
Download https://deno.land/std@0.53.0/fmt/colors.ts
Download https://deno.land/std@0.53.0/testing/diff.ts
Download https://deno.land/std@0.53.0/bytes/mod.ts
Download https://deno.land/std@0.53.0/path/mod.ts
Download https://deno.land/std@0.53.0/path/win32.ts
Download https://deno.land/std@0.53.0/path/posix.ts
Download https://deno.land/std@0.53.0/path/common.ts
Download https://deno.land/std@0.53.0/path/separator.ts
Download https://deno.land/std@0.53.0/path/interface.ts
Download https://deno.land/std@0.53.0/path/glob.ts
Download https://deno.land/std@0.53.0/path/_constants.ts
Download https://deno.land/std@0.53.0/path/_util.ts
Download https://deno.land/std@0.53.0/path/_globrex.ts
Compile file:///$pathToDir/myFirstDeno/main.ts
Starting server port:  8080

$ curl localhost:8080
Hello World # console.log で指定した内容が出力されます。

import で https://deno.land/std@0.53.0/http/server.ts のようにバージョンを指定して import する方法が少し気になったので調べてみます。

Deno の serve のドキュメントを読むと以下のようになっています。

/**
 * Create a HTTP server
 *
 *     import { serve } from "https://deno.land/std/http/server.ts";
 *     const body = "Hello World\n";
 *     const s = serve({ port: 8000 });
 *     for await (const req of s) {
 *       req.respond({ body });
 *     }
 */

https://deno.land/std/http/server.ts というバージョンなし import で依存を解決してます。

試しに標準の http モジュールを使って実行してみました。

import serve from "https://deno.land/std/http/server.ts"

に書き換えただけです。実行結果は以下。

$ deno run --allow-net main.ts
Download https://deno.land/std/http/server.ts
Warning Implicitly using master branch https://deno.land/std/http/server.ts
Download https://deno.land/std/encoding/utf8.ts
Download https://deno.land/std/io/bufio.ts
Download https://deno.land/std/testing/asserts.ts
Download https://deno.land/std/async/mod.ts
Download https://deno.land/std/http/_io.ts
Warning Implicitly using master branch https://deno.land/std/testing/asserts.ts

#略 

Warning Implicitly using master branch という警告が出るようになってしまいました。

これは一体どういうことなのだろう?標準ライブラリでもバージョニングをいれることが推奨されているのかもしれないですが、ちょっとまだお作法がよくわかっていません。

もしかして暗黙的に master を使っていると master はよく変更が加わるもので、何かのアップデートがあった時にコードが壊れてしまう可能性があるから暗黙的に master の標準ライブラリを使用するのは避けるべきなのかもしれません、とか考えてたら書いてありました。

Denoでは、バージョン管理も簡単、importしているURLに@^${バージョン番号}を追加するだけです。

qiita.com

ファイルレベルでバージョン管理されてるのは確かに良さそうです。
この辺ルールを決めないと自由度上がりすぎてプロジェクト全体で特定バージョンを使いたいユースケースに対応し切れないですが、そういうことを嫌った結果なのかもしれませんね。知らんけど。
(...node_modules はデカイしいやだよね)

また、別にdeps.tsというファイルを用意し、そこでバージョンを一括管理することもできます。

deps.ts なんてものもあるんですね。これは別の機会に調べてみようと思います。

VSCode plugin

Deno の VSCodeプラグインがすでに登場してました。Install extentions で検索するとわかりますが、いくつか Deno 関連のプラグインが出てきます。

僕は現時点(20200527) で公式の以下を使ってみることにしました。

marketplace.visualstudio.com

Configuration に記載されてる設定の property を Setting.json に追加します。

// deno
"deno.enable": true,
"deno.alwaysShowStatus": true,
"deno.importmap": null,
"deno.autoFmtOnSave": "", //未実装なのでなし

Node Modules

最初にサーバーを起動した時に Download... と表示されたように deno は import に宣言しておけば、local に存在しない依存は実行時に自動で取得してくれるっぽいです。
(なんとなく Go Modules みたいだなと感じました。)

node のエコシステムは deno には必要ないんですね。
(感動)

Working on docker

Deno の動作をローカルで確認したところで次に Docker で Deno を動かします。

Deno の公式の Dokcer イメージは以下です。

https://github.com/hayd/deno-docker

Build & Run

Dockerfile を用意します。

FROM hayd/alpine-deno:1.0.2

EXPOSE 1993 # The port my application listen to.

WORKDIR /app 

USER deno

COPY deps.ts .
RUN deno cache deps.ts

COPY . .

RUN deno cache main.ts

CMD ["run", "--allow-net", "main.ts"]
$ docker build -t emahiro-deno .
Sending build context to Docker daemon  8.192kB
Step 1/9 : FROM hayd/alpine-deno:1.0.2
1.0.2: Pulling from hayd/alpine-deno
c9b1b535fdd9: Already exists
052c7836b622: Pull complete
9460a82e0a88: Pull complete
eef61d161c0b: Pull complete
Digest: sha256:1a759550e5cc76980f5ebc3a599c79e6fc6e5cc34827083edd1225a25ac4dd12
Status: Downloaded newer image for hayd/alpine-deno:1.0.2
 ---> 8f192534bc9d
Step 2/9 : EXPOSE 8080
 ---> Running in 13d038204325
Removing intermediate container 13d038204325
 ---> 31e5525dd8a6
Step 3/9 : WORKDIR /app
 ---> Running in 7f5d89735bd2
Removing intermediate container 7f5d89735bd2
 ---> b9b01c114460
Step 4/9 : USER deno
 ---> Running in 90aea4eca3b0
Removing intermediate container 90aea4eca3b0
 ---> 9bba107b8b99
Step 5/9 : COPY deps.ts .
 ---> a05bfbd4d8a7
Step 6/9 : RUN deno cache deps.ts
 ---> Running in 24022494bfd8
Compile file:///app/deps.ts
Removing intermediate container 24022494bfd8
 ---> c4517e93e4d6
Step 7/9 : COPY . .
 ---> c03cb478f6df
Step 8/9 : RUN deno cache main.ts
 ---> Running in 8df5fad63cbd
Download https://deno.land/std@0.53.0/http/server.ts
Download https://deno.land/std@0.53.0/encoding/utf8.ts
Download https://deno.land/std@0.53.0/io/bufio.ts
Download https://deno.land/std@0.53.0/testing/asserts.ts
Download https://deno.land/std@0.53.0/async/mod.ts
Download https://deno.land/std@0.53.0/http/_io.ts
Download https://deno.land/std@0.53.0/textproto/mod.ts
Download https://deno.land/std@0.53.0/http/http_status.ts
Download https://deno.land/std@0.53.0/io/util.ts
Download https://deno.land/std@0.53.0/fmt/colors.ts
Download https://deno.land/std@0.53.0/testing/diff.ts
Download https://deno.land/std@0.53.0/async/deferred.ts
Download https://deno.land/std@0.53.0/async/delay.ts
Download https://deno.land/std@0.53.0/async/mux_async_iterator.ts
Download https://deno.land/std@0.53.0/path/mod.ts
Download https://deno.land/std@0.53.0/bytes/mod.ts
Download https://deno.land/std@0.53.0/path/win32.ts
Download https://deno.land/std@0.53.0/path/posix.ts
Download https://deno.land/std@0.53.0/path/common.ts
Download https://deno.land/std@0.53.0/path/separator.ts
Download https://deno.land/std@0.53.0/path/interface.ts
Download https://deno.land/std@0.53.0/path/glob.ts
Download https://deno.land/std@0.53.0/path/_globrex.ts
Download https://deno.land/std@0.53.0/path/_constants.ts
Download https://deno.land/std@0.53.0/path/_util.ts
Compile file:///app/main.ts
Removing intermediate container 8df5fad63cbd
 ---> 7c68bae2e695
Step 9/9 : CMD ["run", "--allow-net", "main.ts"]
 ---> Running in 8b34e2020b18
Removing intermediate container 8b34e2020b18
 ---> 8d26b2c23903
Successfully built 8d26b2c23903
Successfully tagged emahiro-deno:latest
$ docker run --name deno-app -d -it --rm -p 8080:8080 emahiro-deno
{$ContainerID}
$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS                    NAMES
7651ddde92f8        emahiro-deno        "deno run --allow-ne…"   About a minute ago   Up About a minute   0.0.0.0:1993->1993/tcp   deno-app

コンテナが起動した状態で curl でHTTPリクエストを送ってみます。

$ curl localhost:8080
Hello World

Docker を使ってローカルでサーバーを起動させることができました。

Deploy to Cloud Run

Cloud Run にデプロイしてみます。

デプロイ手順は こちら

Regionの指定

Cloud Run のリージョンは既に東京があるので東京( asia-northeast1 ) を使用します。これは gcloud run deploy 時に --region フラグで指定しもいいし、 gcloud コマンドの設定を追加しても大丈夫です。

ref: https://cloud.google.com/run/docs/locations?hl=ja

# gcloud の設定を確認
$ gcloud config list

# 東京リージョンの設定
$ gcloud config set run/region asia-northeast1

ref: gcloud config コマンドのリファレンス

Setting Cloud Build

Cloud Run を使うには Cloud Build を有効にする必要があります。

Cloud Build, Cloud Run, Container Registry, and Resource Manager API を有効にします。

ref: Cloud Run へのデプロイ#始める前に

ビルド済みの既存のイメージからコンテナを作成しない場合は Container Registry は必要ありません。

Cloud Build は API を有効にしたのち Cloud Build を使うサービスに 権限 を付与しないといけないので Cloud Build > 設定 で Cloud Run 管理者を有効にします。Cloud Run を有効にすると追加でサービスアカウントへの権限付与も求められるので権限を付与します。

最終的には以下のようになります。

Deploy

コンテナを Cloud Registry に登録

$ gcloud builds submit --tag gcr.io/$PROJECT_NAME/emahiro-deno:latest

Deploy to Cloud Run

gcloud run deploy hello-deno --image gcr.io/$PROJECT_NAME/emahiro-deno --region asia-northeast1 --platform managed --allow-unauthenticated 
Deploying container to Cloud Run service [hello-deno] in project [$PROJECT_NAME] region [asia-northeast1]
✓ Deploying new service... Done.
  ✓ Creating Revision...
  ✓ Routing traffic...
  ✓ Setting IAM Policy...
Done.
Service [hello-deno] revision [hello-deno-00001-geh] has been deployed and is serving 100 percent of traffic at https://hello-deno-$HASH.a.run.app

--platform : 実行環境のPFを指定する。 managed or gke or kubernetes が入ります。基本的には managed で良いです。(ただし region の option が必須。gcloud config set run/region していない場合は)

--allow-unauthenticated : 認証付きリクエストにするかどうか。認証必須の場合は --no-allow-unauthenticated になります。

ref: gcloud run deploy のリファレンス

その他

price

気になったので価格表だけ久しぶりに調べました。まぁ遊ぶくらいなら無料枠で余裕かなと思います。

Cloud Build

Cloud Run

30歳になった

特に意味はないけど節目なのでエントリーを残してみた。

30歳になったからといって特に何かがわかることはないと思う。
引き続きコードは書くし、ブログも少しずつ継続していきたい。

最近本を読む機会がめっきり減っていて良くないと思っているので、積読の消化を2020年残りの半年をかけて少しでも進めていきたい。

仕事で言うと、直近そんなに変化があるわけではないことに加え、別に業界柄年齢で仕事が変わることはないとは思ってはいるものの、やはり30という数字を見るとそろそろ自分一人のマネジメントだけでなく、チームのマネジメントを考えないといけないのではないか?ということを少しずつ感じている。

それがマネージャーという役職なのかまでははっきりと見えていないが、少なくともプロジェクトやプロダクトを超えて、組織にコミットしていくようなアプローチも必要になってくるだろう。
これはどういうことをすればいいのか?そういうチャンスを与えられるのかはさっぱりわからないし、こればかりはタイミングだと思っている。

ただし、最近は コードを書けるだけではダメだ ということを強く感じるようになっている。コードを書くのは楽しいし、何か新しい技術要素を知ることもまた楽しい。
しかし、楽しいだけではダメで、自分が楽しいことに加えて、チーム全体にその楽しさを伝えたり、またはプロダクトへのコミットをもっと高める施策を考えていかなければならないんだろうなと思っている。

7年前に新卒としてこの業界に飛び込んできた時には考えもしなかったことを考えるようになった。

これまた一つの成長なのかもしれない。

Leaning Docker - part1

Overview

Docker について今更ながら入門したのでその記録をつらつらと書いていく。

Summary

Docker について雰囲気でしか理解しておらず、実務でちゃんと使えるレベルになかったので Udemy の「ゼロから始める Docker によるアプリケーション実行環境構築」 を見ながら、今更 Docker の基礎中の基礎について再入門しました。

Docker Hub

Docker向けのコンテナ共有サービス「Docker Hub」

Dokcer Image とは

Docker コンテナの実行に必要なファイルをまとめたファイルシステム(AUFS) OSのライブラリ、アプリケーション、ミドルウェアがすでにインストールされている(RubyPHPを含) Webサーバーを作る場合は nginx や apatch がすでにインストールされている、というイメージ。 イメージのデータはレイヤで構成され read only

Docker コンテナは軽量であることが求められる。 過去のレイヤーのファイルは消えない。削除を実行したコンテナレイヤー上でファイルは削除されるが、履歴は残り続けるのであるレイヤーでファイルを追加した処理は残り続ける。 1度大きなファイルを追加してイメージ化したものをあとのレイヤで削除したとしても、イメージにはその過去追加した大きなファイルは残り続けるのでイメージ全体が肥大化する。 Dockerコンテナはなるべく軽量であることが求められているので、なるべく無駄なファイルがイメージの中に存在しないようにイメージを作成することが大事。 Dockerイメージがデカイ -> イメージのDL, Docker Hub 等へのアップロードに時間がかかる、ということ。 イメージを作成するときはサイズに注意。

Docker コンテナでのコマンドの実行

docker run docker/whalesay cowsay Hello を実行する。 ※ docker/whalesay は Docker 社が公開してる公式のアスキーアートのイメージ。docker run でコマンドを実行する練習をすることができる。

docker run $ImageName {$command} {$args} で docker コンテナ内部で指定したコマンドを実行できる。

$ docker run docker/whalesay cowsay Hello
Unable to find image 'docker/whalesay:latest' locally
latest: Pulling from docker/whalesay
Image [docker.io/docker/whalesay:latest](http://docker.io/docker/whalesay:latest) uses outdated schema1 manifest format. Please upgrade to a schema2 image for better future compatibility. More information at [https://docs.docker.com/registry/spec/deprecated-schema-v1/](https://docs.docker.com/registry/spec/deprecated-schema-v1/)
e190868d63f8: Pull complete
909cd34c6fd7: Pull complete
0b9bfabab7c1: Pull complete
a3ed95caeb02: Pull complete
00bf65475aba: Pull complete
c57b6bcc83e3: Pull complete
8978f6879e2f: Pull complete
8eed3712d2cf: Pull complete
Digest: sha256:178598e51a26abbc958b8a2e48825c90bc22e641de3d31e18aaf55f3258ba93b
Status: Downloaded newer image for docker/whalesay:latest
_______
 < Hello >
  -------
     \
      \
       \
                     ##        .
               ## ## ##       ==
            ## ## ## ##      ===
        /""""""""""""""""___/ ===
   ~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ /  ===- ~~~
        \______ o          __/
         \    \        __/
           \____\______/

こんな感じ。

Docker Imageの管理

docker images を叩く。
現在 local に存在する image の一覧を確認できる。

イメージのリポジトリ名を変更する

docker tag docker/whalesay emahiro_whalesay で local のイメージに新しくタグを追加することができる。

$docker images
emahiro_whalesay latest 6b362a9f73eb 4 years ago 247MB

こんな感じ。

タグを打つ

docker tag docker/whalesay emahiro_whalesay:emahiro で元々のイメージにタグを打って分けることが可能になる。

$ docker images
emahiro_whalesay emahiro 6b362a9f73eb 4 years ago 247MB
emahiro_whalesay latest 6b362a9f73eb 4 years ago 247MB

こんな感じ。

イメージをビルドする

イメージを構築するには Dockerfile (イメージの定義ファイル) Dockerfile からイメージを構築することを イメージビルド と言う。 Dockerfile には 命令 引数 と言う形式で構築手順を記載していく。 ex. FROM docker/whalesay:latest は新しいイメージをビルドするときの大元(タネ)になるイメージに docker/whalesay イメージの latest タグを使う、と言うことを表現しています。

ビルド時に指定する命令1つあたりが1レイヤーとして元となるベースイメージに追加される、と言う意味になる。

よくわかってなかったDocker build のあれこれ

  • CMD 命令 -> コンテナが作成された後に実行するコマンドを指定する命令。
  • -t optison: ビルドした Docker イメージに名前をつけるオプション。ex. docker build -t emahiro_whalesay .
  • ビルドコンテキスト: イメージを作成する際にアクセスできるディレクトリやファイルの範囲を示す。
    • 特に指定がなければ . でビルドしたい Dockerfile と同じ階層のカレントディレクトリを指定する。
    • イメージ内に含めたいファイルやディレクトリを参照する場合は、ビルドコンテキスト内であればコピーすることができる。ビルドコンテキスト外のファイルはイメージ構築時に参照することができない。
    • イメージビルド時にビルドコンテキストないのファイルやディレクトリはまとめて Docker deamon に送信される。大きなファイルがビルドコンテキストに含まれる場合に、ファイルの転送処理に時間がかかるので、不要なファイルはビルドコンテキストに含まない方が吉。
    • ビルドコンテキストに含まれるファイルが全てイメージに取り込まれる、と言うわけではなく、イメージビルドした際に一時的に Docker deamon に転送されるだけで COPYADD と言った命令で明示的にイメージ内にファイルをコピーする命令を使わなければイメージ内にビルドコンテキスト上のファイルが保存されることはない。
    • Docker build コマンドはデフォルトでビルドコンテキスト状にある Dockerfille が読み込まれる。

サンプル

$ docker build -t emahiro-whale .
Sending build context to Docker daemon 2.048kB

Sending build context to Docker daemon 2.048kB はビルドコンテキストを Docker deamon に転送している処理。

ビルドキャッシュ

各ステップのビルドの結果をキャッシュとして保持したもの。 Dockerfile の内容が同じであればキャッシュが使用されて、実際の命令はスキップされる。

$ docker build -t emahiro-whale .
Sending build context to Docker daemon 2.048kB
Step 1/3 : FROM docker/whalesay:latest
---> 6b362a9f73eb
Step 2/3 : RUN apt-get -y update && apt-get install -y fortunes
---> Using cache # キャッシュを使う
---> 2a92623b6954

※ 毎回動作が変わるようなコマンドには注意が必要 ( ex. apt-get -y update など)

なぜならば、apt-get -y update を記載した本人は毎回パッケージリストを更新することを期待しているかもしれないが、Dockerfile 上はコマンドが変わらないのでビルドキャッシュが利用されてしまい、実際の動作では package リストが更新されない、と言う問題が発生するからである。 --no-cache を使うとキャッシュが使用されずに全てのステップが実行される。

Image をアップロードする

学習なので Docker Hub にアップロードする。このイメージのアップロード先については Google Cloud Registry や Amazon Elastic Container Registory などクラウドベンダーが用意してるコンテナイメージのホスティングサービスもある。 ローカルからイメージをビルドしてアップロードする場合、リモートのホスティング環境にすでに同名のイメージが存在するケースではタグを切らない場合にイメージが上書きされてしまうので注意が必要である。

  1. Docker image をホスティングしてるサーバーへのログインする。事前にログインをしておく必要がある。
    1. docker login -> デフォルトで Docker Hub へのログインをする。
    2. タグ付のルール -> $DockerID/$Image:$Tag ex. docker tag emahiro-whale emahiro/emahiro-whalesay:v1
  2. Docker Hub へ Push する。 docker push emahiro/emahiro-whalesay:v1

※ Docker Hub では事前にリポジトリを作成しておかなくても、$DockerID/$Image:$Tag のフォーマットで push すれば自動でリポジトリが作成されます。

Web サーバーを Docker で構築する

Nginx) のイメージを使用して Web サーバーを立ててみる。

Nginx イメージについて

使用するのは Exposing external port に記載されてる docker run コマンド。

$ docker run --name $ContainerName -d \
    -p $HostPortNum:$ContainerPortNum \
    $ImageName

$ContainerName で指定したコンテナ名はコンテナを識別したり、コンテナ操作を行う上で必要になるのでできるだけ設定するようにしておくのが吉。

-p はコンテナのポートをコンテナ外に公開する設定。前が外部に公開する番号で、後ろがコンテナにマッピングされているポート番号。

docker run --name emahiro-nginx -d -p 8080:80 nginx
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
afb6ec6fdc1c: Pull complete
b90c53a0b692: Pull complete
11fa52a0fdc0: Pull complete
Digest: sha256:30dfa439718a17baafefadf16c5e7c9d0a1cde97b4fd84f63b69e13513be7097
Status: Downloaded newer image for nginx:latest
24e6863779c15bcd1580808b9efcd02ac8c871827de1f0fae12455a6bb840c06 # 起動したコンテナのID

コンテナを起動・停止・削除をする時には末尾のコンテナIDかコンテナ名を使用する。

-d はデタッチモード。デタッチモードの場合に foreground でコンテナが動作するわけではないので、コンテナを立ち上げたまま他の操作をすることが可能。

デタッチモードを指定しないと foreground で nginx のコンテナが動作しているので Ctnl + C でコンテナを停止すると nginx の動作も停止します。

ホスト上の HTML を Nginx コンテナで公開する(バインドマウント)

Docker Hub の Nginx) に記載されている Hosting some simple static content に習って進める。

Sample.

$ docker run --name some-nginx -v /some/content:/usr/share/nginx/html:ro -d nginx

  • -v : Volume の v を意味している。
  • 静的なHTMLファイルを Nginx で公開するものを想定している。
$ docker run --name $ConteinarName -d \
    -v $HostDir:$ContainerMountedPoint:$Option \
    -p $HostPortNum:$ContainerPortNum \
    $ImageName

-v の引数がコロン区切りで3つに分かれている。

  • $HostDir: コンテナにマウントするホスト側のディレクト
  • $ContainerMountPoint :コンテナ側のディレクトリ。Nginx コンテナにおいては /usr/share/nginx/html が公開対象のドキュメントルートになる。
  • $Options : 権限を指定できる。 ex. ro マウント先のコンテナに読み取り専用でマウントする指定。なくても動作が可能。

※ 引数の指定は 絶対path で指定することが必要。

pwd コマンドを使えば現在いるディレクトリの絶対パスを表示することが可能。(だからよくサンプルとかで $PWD と言う環境変数がよく出てきたのか、と言うことを今更理解した。)

Sample

docker run -it --name emahiro-nginx \
-v $PWD/assets/html:/usr/share/nginx/html:ro \
-d -p 8080:80 \
nginx
6af418943c7300bb2ac9e03f47aab91eb6cf3dbbc0fe87c0796ffa408e10ab43

COPY, ADD 命令

ホストマシン上のファイルをイメージ内にコピーする命令。

サンプルとして、 Nginx の修正した設定ファイルをコンテナ内にコピーしてみる。

編集する設定ファイルを取り出す

docker run --name emahiro-nginx --rm -d nginx

--rm : コンテナを停止した時点で自動でコンテナの削除まで行うオプション。コンテナは通常停止しても停止状態で残り続けてしまう。これにより、同名のコンテナを作成するときなどに名前がバッティングして起動できなくないので、すでに同名のコンテナが存在する場合は削除する必要がある。毎回削除するのは手間なので --rm オプションをつけることで、停止した時にコンテナ自体も削除することで名前がバッティングしたりするケースを避けることができる。

Nginx のコンテナを起動し、設定ファイルを取り出すことのみをするので、デタッチモードで起動する。

デタッチモードで起動したら Nginx の設定ファイルを取得する。

docker cp

ホストマシン → コンテナ へのコピー

$ docker cp $FilePathOnHost \
    $ContainerName(or $ContainerID):$PathToFileOnContainer

コンテナ内のファイル → ホストマシン へのコピー

$ docker cp $ContainerName(or $ContainerID):$PathToFileOnContainer \ 
    $PathToCopyOnHost

設定ファイルをコンテナにCOPYする

Docker ファイルで以下のようにコンテナに転送するファイルを指定します。

FROM nginx:latest
COPY nginx_conf/default.conf /etc/nginx/conf.d/default.conf

そしてビルドコンテキストを . に指定してイメージをビルドします。

$ docker build -t emahiro-nginx:v1 .

ADD 命令と COPY コマンドの違い

COPY コマンドは単純にファイルをコピーする。

ADD 命令は COPY 命令の機能に加えて tar でアーカイブされたファイルをコピー時に自動で展開したり、 COPY 元にURLを指定した場合は、URLからダウンロードしてコピー先に転送するといった動作を行う。

ADD 命令の動作は一見すると名前から類推しづらい動作をするため、ベストプラクティスとしては通常は COPY 命令を使い、ADD 命令に備わった機能が必要な場合のみ ADD 命令を使うことが推奨されている。

コンテナのライフサイクル

前提

  • コンテナとは Docker Image のファイルシステムを元にして作られる一種の仮想環境。
  • コンテナが起動してる間は、コンテナはホストマシンの1プロセスとして動作する。
  • コンテナが作成されてから削除されるまでにいくつものステータスがある。

Created Status

コンテナが作成されてスタートされる前の状態。

docker create を使ってコンテナを作成した状態がこのステータス。

docker create --name status-test -it alpine /bin/sh

-i : コンテナの標準入力を取得して、双方向に接続できるようにするオプション。

-t : コンテナ内にtty を割り当てる。コンテナでシェルを実行して、foreground で実行状態のままにしておきたい時によく使う。

-it の組み合わせてよく使われる。

docker create をしただけでは実行中ではないので docker ps コマンドでは出力されない。 docker ps -a コマンドを利用する。

docker ps -a
CONTAINER ID        IMAGE                     COMMAND                  CREATED             STATUS                    PORTS               NAMES
d1ed34aa3314        alpine                    "/bin/sh"                3 minutes ago       Created                                       status-test

Running Status

コンテナが作成され、Created 状態になった後に Start されると Runninng ステータスになる。

docker run コマンドは create → start がセットになったもの。docker ps で表示さえる Status には起動時間が表示される(=起動時間が表示されているのは Running status)

docker inspect でも起動状態を確認できる。

$ docker inspect status-test
[
    {
        "Id": "abf9fb1cecaa8bdd08e643a41065c2048c072e401823a962997a2fdbedbdf3b0",
        "Created": "2020-05-25T10:20:21.487691823Z",
        "Path": "/bin/sh",
        "Args": [],
        "State": {
            "Status": "running", # これ。
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 2629,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2020-05-25T10:23:29.494591462Z",
            "FinishedAt": "0001-01-01T00:00:00Z"
        },
#略

Paused Status

docker pause コマンドで一時停止させた時にこのステータスになる。

docker pause status-test
status-test
➜  docker git:(il/docker) docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                  PORTS               NAMES
abf9fb1cecaa        alpine              "/bin/sh"           5 minutes ago       Up 2 minutes (Paused)                       status-test

docker inspect でも確認可能。

$ docker inspect status-test
[
    {
        "Id": "abf9fb1cecaa8bdd08e643a41065c2048c072e401823a962997a2fdbedbdf3b0",
        "Created": "2020-05-25T10:20:21.487691823Z",
        "Path": "/bin/sh",
        "Args": [],
        "State": {
            "Status": "paused", #これ
            "Running": true,
            "Paused": true,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 2629,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2020-05-25T10:23:29.494591462Z",
            "FinishedAt": "0001-01-01T00:00:00Z"
        },
#略

Paused Status のときは起動中のコンテナにリクエストを投げたりしても応答ができない場合がある。

(ってことはクライアントのタイムアウトのテストの時とかに使える?)

docker unpause で解除できる。

Restarting Status

コンテナの再起動中のステータス。

通常はすぐに起動しちゃうのでこのステータスを見ることは稀。

Exited Status

コンテナは終了したのに、コンテナが残り続けてるとこのステータスになる。

$ docker ps -a
CONTAINER ID        IMAGE                     COMMAND                  CREATED             STATUS                      PORTS               NAMES
892fdf2e3fb8        hello-world               "/hello"                 15 seconds ago      Exited (0) 15 seconds ago                       recursing_williamson

foreground で動作が終了したコンテナや、 docker stop で停止させたコマンドがこの Exited ステータスになります。

Removing Status

コンテナ削除中のステータス。すぐに削除されちゃうのでこのステータスをみることは稀。

Dead Status

正常に終了できずにゾンビ化したコンテナがこのステータスになる。この状態のコンテナは削除するしかない。通常の docker rm で削除できないので docker rm -f で削除する。

コンテナのシェルに接続する

docker attach を使用する

docker attach $ContainerName(or $ContainerID)

コンテナの pid:1 の標準入出力に接続する。コンテナ起動時のコマンドでシェルを起動した場合は attach するとそのシェルに接続することができる。

ただし起動時にシェルでなく、デーモンを起動していた場合はデーモンの標準入出力に接続してしまう。

起動時に --it オプションを使うことがセットになる。

docker exec を使用する

docker exec は起動してるコンテナ内で任意のコマンドを実行するためのコマンド。

シェルに接続するには -it オプションつきでシェルを実行する。接続したシェルを抜けるには exit コマンドを使います。

$ docker exec -it $ContainerName(or $ContainerID) /bin/bash

docker attach と違い、 exit で抜けてもコンテナが停止することはない。誤ってコンテナを停止させてしまうことを考えると docker exec コマンドの方が安全。

Example

$ docker run --name connect-test -it -d ubuntu /bin/bash
f612509fd241330357446a8d3a275a09c73968ac3fbd3743dee282305b4c9791
$ docker attach connect-test
exit
$ docker ps -a
CONTAINER ID        IMAGE                     COMMAND                  CREATED             STATUS                        PORTS               NAMES
104fb2fb5779        ubuntu                    "/bin/bash"              18 seconds ago      Exited (127) 1 second ago                         connect-test

# docker exec のケース
$ docker exec -it connect-test /bin/bash
root@42933e32d725:/# exit
exit
$ docker ps -a
CONTAINER ID        IMAGE                     COMMAND                  CREATED              STATUS                        PORTS               NAMES
42933e32d725        ubuntu                    "/bin/bash"              About a minute ago   Up About a minute                                 connect-test

exec コマンドのケースではコンテナが停止していないことが確認できます。

Docker commit

docker commit : 存在するコンテナを対象に docker commit を実行した新しく保存するイメージ名、タグ名を指定する → docker commit $ContainerName $ImageName:$Tag

コンテナの状態をイメージとして保存することができる。

docker commit コマンドで何かしら操作をしたコンテナからイメージを作成した場合、コンテナ内で行われた作業はどこにも明確な記録として残らなくなってしまうこと。

通常、Docker Image を作成する際に Dockerfile で実行された各コマンドはイメージの各レイヤーとして何のコマンドが実行されたかが記録されています。それを docker history で確認することが可能ですが、コンテナ内部で操作したコマンドは docker history コマンドの結果には出力されません。

Dockerfile で Image をビルドした場合は Dockerfile からもどういったコマンドを実行して作成したイメージなのかをあとから確認することもできる。

どのような操作で作成されたイメージなのかわからなくなってしまうと、何が含まれていて、どのような変更が加えられているのか把握しづらくなる。つまり使いづらい Docker Image になってしまう。

通常は Dockerfile を使うのが吉。

# ubuntuをベースに tempfile を加えたイメージを作成する。 
$ docker run --name commit-test -it --rm -d ubuntu /bin/bash
e61b85a3f4cd6cbf457e0b4bd25d40e7ffe1cbd430f25c8a4b4dd811b22ac585
$ docker exec -it commit-test /bin/bash
root@e61b85a3f4cd:/# cd tmp
root@e61b85a3f4cd:/tmp# dd if=/dev/zero of=tempfile bs=1M count=10
10+0 records in
10+0 records out
10485760 bytes (10 MB, 10 MiB) copied, 0.00829059 s, 1.3 GB/s
root@e61b85a3f4cd:/tmp# ll
total 10248
drwxrwxrwt 1 root root     4096 May 25 16:42 ./
drwxr-xr-x 1 root root     4096 May 25 16:40 ../
-rw-r--r-- 1 root root 10485760 May 25 16:42 tempfile
root@e61b85a3f4cd:/tmp# exit # 一旦コンテナを抜ける。
$ docker commit commit-test commit-test:v1 # tempfile を作成した状態でイメージを作成する。

docker history

コンテナでどんな処理を行ったのかイメージのレイヤーが順に出力される。上から順に新しく追加されたレイヤーになっている。

docker history commit-test:v1
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
af6d001d6055        2 minutes ago       /bin/bash                                       10.5MB # 10M を追加したレイヤー
1d622ef86b13        4 weeks ago         /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B
<missing>           4 weeks ago         /bin/sh -c mkdir -p /run/systemd && echo 'do…   7B
<missing>           4 weeks ago         /bin/sh -c set -xe   && echo '#!/bin/sh' > /…   811B
<missing>           4 weeks ago         /bin/sh -c [ -z "$(apt-get indextargets)" ]     1.01MB
<missing>           4 weeks ago         /bin/sh -c #(nop) ADD file:a58c8b447951f9e30…   72.8MB  

CREATED BY には bin/bash の情報しか載っておらず、10Mを増やすのにどんな処理をしたのかは、このレイヤーを追加した人にしかわからない。

Infrastructure as code の観点からも、Docker においては Dockerfile を使うことが重要とされている。

Docker link

--link オプションはいずれ廃止される可能性があるので詳細は割愛。

-e : 引数の環境変数をコンテナに設定するオプション。

$ docker run --name $ContainterName -e ENV_VALUE="Hoge" -d $ImageName

$ContainerName で作成してコンテナ内で ENV_VALUEHoge という値がわかっていることになる。

$ docker run --name emahiro-ubuntu -it --rm -e EMAHIRO="emahiro" -d ubuntu /bin/bash
1e5d343ce111d9c5e26cfab553faa5d91c95a66fc8cfe9592581cd5f52f05b3b
$ docker exec -it  emahiro-ubuntu /bin/bash
root@1e5d343ce111:/# echo $EMAHIRO
emahiro

-e オプションで指定した環境変数がコンテナで設定されてることがわかる。

※ 随時更新 - Docker で よく使うコマンド

Document

https://docs.docker.com/

Commands

pull

 https://docs.docker.com/engine/reference/commandline/pull

rmi

rmi

ImageID か ImageName を指定して docker image を削除する。

docker rmi $ImageID( or $ImageName)

ex. docker rmi (-f) docker/whalesay

images の削除はタグ名を指定しない限りは latest が削除される。

remove images all

https://www.digitalocean.com/community/tutorials/how-to-remove-docker-images-containers-and-volumes

docker images を削除してもコンテナで使用中だと conflict (使用中だよ!)エラーが発生する。
そのため docker ps -a で起動していないか確認し、まず docker stop CONTAINER_ID でコンテナを停止する。
その後 docker rm コンテナID でコテな削除 さらにその後に docker rmi する。

remove none images

qiita.com

tag

docker tag IMAGE_ID {{ REPO_NAME:TAG_NAME }}

none の imageに REPO_NAME と TAG_NAME をつけることができるので none があるときは暫定的な名前とつけることもある。

run

docker コンテナを実行する。これは pull -> create -> start の3コマンドがセットになったもの。

docker コンテナの shell でログインするときに使う

docker run -it {{ IMAGE }} /bin/bash

これが一番簡単。 IMAGE に入るのは mysql:5.7 など {tag}:{version} がイメージ名

ex. docker run -it ubuntu bash
ubuntu の最新のイメージを取得して bash でログインすることができる。

exec

docker コンテナ状でプロセスを実行したいときに使う

例えば mysql のクエリを打ちたい時は以下

docker exec -it {{ container name }} mysql -u root -e "select * from hoge ....;"

※ {{ container name }} は docker ps で出力される NAMES の部分

ImageID, Image Name, ContainerID ContainerName はそれぞれ違う。docker においては Image をベースに作られるのがコンテナ。

inspect

docker inspect emahiro_whalesay

$ docker inspect emahiro_whalesay
[
    {
        "Id": "sha256:6b362a9f73eb8c33b48c95f4fcce1b6637fc25646728cf7fb0679b2da273c3f4",
        "RepoTags": [
            "docker/whalesay:latest",
            "emahiro_whalesay:emahiro",
            "emahiro_whalesay:latest"
        ],
        "RepoDigests": [
            "docker/whalesay@sha256:178598e51a26abbc958b8a2e48825c90bc22e641de3d31e18aaf55f3258ba93b"
        ],
# 略
}

コンテナの設定情報(host名や環境変数、コンテナ実行時のコマンド情報など) が入ってくる。 その他 OS の情報やサイズ、ファイルシステムの情報も含まれる。

stop

コンテナを停止する。

  • 起動中の全コンテナの停止: docker stop $(docker ps -q)
  • 起動中の全コンテナの削除: docker rm $(docker ps -q -a)
  • 前イメージの削除: docker rmi $(docker images -q)

-q optison は ContainerID や ImageID のみを表示する option.

qiita.com

GCP のセットアップを行う

サマリ

仕事では AWS をメインで使ってるのもあって、GCP を最近全然いじらなくなっていたのですが、久しぶりにいじるかと思い立ったので、 GCP の環境を1からセットアップします。

Set up for Google Cloud SDK

ドキュメント はこちら。
macOSでのクイックスタートは こちら

ドキュメント中に任意の場所に展開すればと記載してますが $HOME がいいと思います。

 $ mv Downloads/google-cloud-sdk ./
 $ ./google-cloud-sdk/install.sh
 Welcome to the Google Cloud SDK!
 
 To help improve the quality of this product, we collect anonymized usage data
 and anonymized stacktraces when crashes are encountered; additional information
 is available at <https://cloud.google.com/sdk/usage-statistics>. This data is
 handled in accordance with our privacy policy
 <https://policies.google.com/privacy>. You may choose to opt in this
 collection now (by choosing 'Y' at the below prompt), or at any time in the
 future by running the following command:
 
     gcloud config set disable_usage_reporting false
 
 Do you want to help improve the Google Cloud SDK (y/N)?

あとはぽちぽち設定していきます。 途中で shell を更新してくるので、すべての設定が完了したら source コマンドでシェルを再起動します。

 which gcloud
 $HOME/google-cloud-sdk/bin/gcloud

PATH が通ってることを確認したら gcloud init でセットアップを開始します。
最初にどの Google アカウントでログインするのか確認されますので、自分のセットアップしたい Google アカウントを洗濯して、https://cloud.google.com/sdk/auth_success のページが出れば認証が完了します。 local にインストールした Google Cloud SDK に複数のプロジェクトと紐づけるときは再度 gcloud init を叩いて

 gcloud init
 Welcome! This command will take you through the configuration of gcloud.
 
 Settings from your current configuration [default] are:
 core:
   account: ema.hiro@gmail.com
   disable_usage_reporting: 'False'
   project: emahiro-dev
 
 Pick configuration to use:
  [1] Re-initialize this configuration [default] with new settings
  [2] Create a new configuration

このプロンプトが出てきた際に 2 を選択します。こうすれば別の Google アカウントとも紐づけることができます。

Google Cloud SDK を動かすための Credentials は$HOME/.config/gcloud/legacy_credentials/{$GoogleAcount}/adc.json にあります。

予算のアラートを設定する

お支払い(Billing) -> 予算とアラートから設定します。デフォルトで All Resource Budgets があるのでこの予算設定を使います。
All Resource Budget で自プロジェクトで使う全ての GCP のサービスに予算のアラートをかけることができるので安全です。

f:id:ema_hiro:20200522183419p:plain

僕は以下のように設定しました。

f:id:ema_hiro:20200522183352p:plain

その他

何か思いついたら載せます。
とりあえずサクッと gcloud コマンドが動いたのでこのエントリはこれでおしまい。

Setting Explorer in VSCode

Overview

VSCodeExplorer をカスタマイズしたお話です。

Explorer 以外を消す

デフォでは

  • Open Editor
  • Outline(ファイル内で定義されてる関数一覧とか)
  • Explorer (プロジェクトの一覧)

がありますが、一番したの Explorer 以外消したいなーと思ったので消す方法を探しました。それが以下。

github.com

github.com

OutLine は setting.json から消せるものかと思って色々調べてましたが、普通にUI操作でした。

その他

Timeline view

ファイルごとにコミットログとどの変更でその差分が入ったのか調べたい時があります。
git blame すればいいんですが、具体的な差分まで調べようと思うと git 力が問われます。

そんな時に VSCode の Timeline view の機能を知りました。
Cmd + Shift + P で Timeline... と検索すると出てきますが、Explorer の画面にコミット履歴とそのコミットにおける差分が pane に描画されます。

地味に便利だなーと思ったので書きました。

defer の順序

よく忘れるので備忘録。

https://play.golang.org/p/n5aHnATxXMr

上記の例だと cb() が実行された時点で呼ばれ b が出力される。
defer は関数を抜けるときに呼ばれるので cb()() を宣言すると func cb() func() の return で指定した関数が呼ばれる。

つまり defer cb()() では最初と最後にそれぞれ cb() で実装した内容が呼ばれることになる。

追記: メソッドを繋いだときの挙動

logger や trace を使うときに多いですが、defer で関数から抜けるときに Finish したり、Flush してメモリを解放する処理を行いたいケースがあると思います。
そう言った場合でも defer で一括りにしちゃうことが可能です。
以下のケースでが New が実行されるのは関数が呼び出された直後ですが、Finish が呼ばれるのは関数を抜けるときになります。

ref: https://play.golang.org/p/3U6WsyEJzLx

エウレカに入社して1ヶ月が経ちました

まぁなんてことないタイトルの通りの話なんですが、転職して1ヶ月(少しアルバイトもしていたので出社開始からは1ヶ月半くらい)経ち、いろいろ環境が変わったのでその記録を書きます。

何してるの?

Gopher

変わらず Gopher です。Go を書いてます。

詳しくは会社の Wantedly でエントリを書いたので読んでみてください。

www.wantedly.com

何か変わった?

GCP -> AWS

ずっと GCP の世界で過ごしてきましたが、インフラは AWS になりました。ただ、ほぼ何もわかりません。 AWS の概要をつかめる Udemy を教えてもらったので GW を使って概要をさらってみるつもりです。
出てくる単語すら何もわからないレベルなので。

マイクロサービス -> モノリス

前職はずっとマイクロサービスの世界で生きてきましたが、今はモノリスな設計の中で開発しています。
マイクロサービスを運用してた頃の辛みも知った上でモノリスを触ると、結構色々な発見があって面白いです。
流行りの技術を使っていても、数年運用された歴史を持つコードはやはり古く、またコードベースが大きいのでCIも遅かったり、まだまだ改善の余地は多そうかなと感じてます。

副業いったん辞める

あと、副業で関わっていた会社を一旦離れました。
タイミングの問題なので特にコメントすることもないのですが、ちゃんとスタートアップで働いてみたのは初めての経験だったので、学ぶことも多かったです。

そんなにやりたいっていう温度感でもないですが、現在少し時間が空いてるので副業のお話があれば検討できます。 こんなご時世ですが、事業に直結しない緊急度は低いが重要なタスク(CI整備とかソフトウェアのバージョンアップとか)周りを進めることは得意です。
※ 技術スタックは Go に限ります。

リモートワーク

多分これが一番大きな変化かなと思います。WHOのパンデミック宣言があった3月末以降原則リモートワークに移行して、在宅で勤務をしています。
僕は場所で仕事モードに切り替わる人間だったので、これはめちゃくちゃ影響が大きかったです。
ただ、もう1ヶ月くらいフルリモートで作業してるので流石になれてきました。

リモートに合わせて、自宅の設備をバージョンアップしたのでなんとか作業をできています。
(この設備投資については会社で補助が出たのでとても感謝してます。)

補助の内容は以下のエントリに詳しく載ってます(僕の買ったものも載ってます)

medium.com

総じて

時流もあり、働く環境は想像以上に大きく変わりましたが、やることは至って変わってないです。
引き続き頑張るぞい。

エウレカに入社しました

本日、3/16より株式会社エウレカに入社しました。

引き続き Gopher です。
ベイスターズとブレイブサンダースも変わらず応援してます。

働く場所は渋谷から赤羽橋の近くになります。
麻布十番にオフィスから歩いていけますが、渋谷と空気感が違ってまだ馴染めません。

前職より出社時刻が早くなるので「朝起きられるのか?」というのが最大の懸念事項でしたが、今のところ大丈夫そうです。

そういえば、オフィスの交差点を挟んだ向かい側に TAILORED CAFE があったので、今度利用してみようと思います。

Go1.14 をサポートしました

Go の Release Policy に合わせて、以下のリポジトリを Go.1.14対応しました。
合わせて Go1.12 のサポートを切りました。

Each major Go release is supported until there are two newer major releases.

ref: Release History - The Go Programming Language

github.com

github.com

github.com

TSLint -> ESLint に乗り換える

Overview

ESLint から TSLint に乗り換える手順について記載します。
サンプルとして自分で作成してる Firebase のプロジェクトで乗り換えた手順を記載しました。
対象は TypeScript で記載されている Functions のコードになります。

乗り換え手順

tslint-to-eslint-config を使用します。

$ npx tslint-to-eslint-config
npx: 54個のパッケージを4.37秒でインストールしました。
✨ 31 rules replaced with their ESLint equivalents. ✨ 
❗ 3 ESLint rules behave differently from their TSLint counterparts ❗
  * no-redeclare:
    - ESLint does not support check-parameters.
  * no-invalid-this:
    - Functions in methods will no longer be ignored.
  * no-void:
    - ESLint does not support ignoring arrow function shorthand. 
⚡ 2 packages are required for new ESLint rules. ⚡
  import
  eslint-plugin-import 

✅ All is well!

TSLint で設定したルールで ESLint に乗り換えることができなかったものについては警告として出力されるので、ESLint のルールで代用できなかを検討すると良さそうです。

Firebase で Functions を使用してるケースでは、functions ディレクトリのデフォルトの .gitignore ファイルに **/*.js が記載されていて、このままだと新しく生成された .eslintrc.js が ignore されてしまうので、 !.eslintrc.js を追記します。

TSLint の削除

  1. eslint のプラグインを入れます。
$ npm install --save-dev eslint @typescript-eslint/parser @typescript-eslint
  1. package.jsonスクリプトから tslint を外します。
- tslint --project tsconfig.json
+ eslint --fix ./src/**/*.ts // ./XXX/**/*.ts で XXX 配下の全ての ts ファイルに eslint をかけます。
  1. tslint の依存を切ります。
- "tslint": "^5.12.0",

ESLint をかける

$ npm run lint

> functions@ lint /Users/hiromichi.ema/emahiro/github.com/emahiro.dev/functions
 > eslint --fix ./src/**/*.ts  
 /Users/hiromichi.ema/emahiro/github.com/emahiro.dev/functions/src/index.ts
   1:1  error  Definition for rule '@typescript-eslint/no-param-reassign' was not found  @typescript-eslint/no-param-reassign
   1:1  error  Definition for rule 'import/no-deprecated' was not found                  import/no-deprecated
   1:1  error  Definition for rule 'import/no-extraneous-dependencies' was not found     import/no-extraneous-dependencies
   1:1  error  Definition for rule 'import/no-unassigned-import' was not found           import/no-unassigned-import

# 略

幾つのかのルールが ESlint に定義がないと言われます。
ルールがないものは適宜書き換える必要があります。
このタイミングで定義が ESLint にないと言われたものについては以下です。

- "@typescript-eslint/no-param-reassign": "error",
+ "no-param-reassign": "error",

ref: no-param-reassign

1:1  error  Definition for rule 'import/no-deprecated' was not found               import/no-deprecated
1:1  error  Definition for rule 'import/no-extraneous-dependencies' was not found  import/no-extraneous-dependencies
1:1  error  Definition for rule 'import/no-unassigned-import' was not found        import/no-unassigned-import

import 周りについては eslint-plugin-import を参考に plugin を追加します。

$ npm i --save-dev eslint-plugin-import

.eslintrc.js の plugin に import を追加します。

- "@typescript-eslint"
+ "@typescript-eslint",
+ "import"

これで今回当たったESLint の未定義ルールについては置き換えが完了しました。

TSLint -> ESLint の過程で error Definition for rule 'XXXXX' was not found のエラーが ESLint で発生したら、ルールを置き換えられないか?or 足りない plugin がないかということを調査してみると良さそうです。

VSCode で TypeScript に ESLint を使う

Setting.json に以下を追記します。

// eslint
"eslint.workingDirectories": [{"mode": "auto"}]

ref: https://github.com/microsoft/vscode-eslint/issues/881

設定後に Cmd + Shift + P で ESLint - Fix all auto-fixable problems. が使えるようになります。
var i = 0 などを適当に書いてみて、no-used-vars の警告が出ていれば動作してるとみて良さそうです。

iTerm2 が Dock にアプリが表示されなくなる問題

以下の設定を ON にするとDock で iTerm が表示されなくなり、タブ移動もできなくなる。不便。
新しく iTerm2 を入れたらデフォでONになってる気がした。Offると良い。

f:id:ema_hiro:20200303015752p:plain