emahiro/b.log

Drastically Repeat Yourself !!!!

ghq を使い始める

Overview

特に避けていたわけではないですが、これ!っていうメリットが特に感じていなかったので ghq を使っていなかったのですが、ふと思い立って使い始めたのでその記録です。

Install ghq

GIthub の README に書いてある通りです。

$ go get github.com/x-motemen/ghq

brew でもインストールできます。

ghq.root ディレクトリの設定

ghq での探索対象を設定します。
ghq の設定には ~/.gitconfig の設定を使います。
自分は普段 ~/src/github.com というディレクトリ構成で個人のPC環境を作っているので、 .gitconfig に以下の設定を追加しました。

[ghq]
root = ~/src/github.com

これで ghq list を実行した時に local の ~/src/github.com を探索対象にしてくれます。
ちなみにdefault では ~/ghq になるみたいです。

alias の設定

エイリアス を設定して、一発で cd $(ghq root)/$(ghq list | peco) を使えるように .zshrc に以下を追加しました。

alias g='cd $(ghq root)/$(ghq list | peco)'

peco とセットにして使うことでインクリメンタルサーチを使えてかつ、その指定したディレクトリに移動までできるようにしています。

まとめ

調べればわかることばかりですが、ghq をとりあえず探索のみで使っているけどシンプルでいい感じです。
ディレクトリ移動は楽になりました。

See Also

VSCode で GitHub と連携する

vscode-githubの画像
vscode-github

Overview

local 環境で VSCode で作業することがほぼベースになってきたので、VSCodeGitHub を連携させて VSCode 上からできることを増やすために設定を追加したのでその記録を記載します。

GitHub for VSCode

VSCode は少し前から VSCode単体で GitHub と連携できるようになっています。 https://vscode.github.com/Add GitHub for Visual Studio Code を選択すれば連携できます。 VSCode からも左下のアカウントマークを押下して、連携シーケンスに移行できます。

vscode.github.com

連携すると設定周りが Sync されるようです。今まで VSCode での設定の共有といえば Setting Sync でしたが今後は VSCode 備え付けの GitHub ログインで良さそうです。
設定の同期機能については以下に詳しく記載されています。

code.visualstudio.com

code.visualstudio.com

GitHub Pull Requests and Issues

GitHub 上の PullReuqest や Issue を VSCode 上から操作できるようになります。

marketplace.visualstudio.com

コードレビューするときはローカルでチェックアウトして実際のコードをみながらレビューする、ということを手間に思うことがあって(それもどうなんだ、、、というツッコミはあると思います。)提出されたファイル差分のみでレビューすることが多かったのですが、VSCode 上でチェックアウトできますし、そのまま VSCode 上で補完や Code Jump も使えるので、これでどれくらいレビューが楽になるのか、その辺を使いながら見てみようと思います。

こういったツールは今までもいくつか出てましたが、private リポジトリも含めて連携しちゃうので権限周りを考えるとちょっと及び腰でした。ただ、このツール自体は GitHub 純正のものなので、全面信頼するわけではないですが、ある程度信頼性があると踏んで使い始めてみてます。

概要は以下に記載してあります。

code.visualstudio.com

VSCode から Issue を作成する

GUI から Issue を作成します。

テンプレートが作成されますので、Issue に記載したい内容を載せて右上のチェックマークを押下します。

Issue が作成されます。Open Issue で実際の Issue に遷移できます。

実際に作成された Issue は以下です。

github.com

VSCode から Pull Request を作成する

まずコードを変更します。 今回はテストなので、自分の学習ログの Readme を書き換えます。

また事前以下のことをやっておきます。

  • ブランチを作る
  • 差分をコミットしておく

実際に VSCode から Pull Request を作成します。

ベースとなるブランチを選択します。デフォルトは master に対する Pull Request になります。

Pull Request のタイトルを選択します。

大体書いてある通りですが

  • commit: ブランチを push して Web GUI から Pull Request を作成する場合のデフォルトのタイトル設定です。よくある、トピックブランチのファーストコミットメッセージがそのまま Pull Request のタイトルになる設定です。
  • branch: ブランチ名が Pull Request のタイトルになります。
  • custom: 自分で Pull Request のタイトルを決めます。今回は custom を使います。

Pull Request のタイトル名を入力して Enter を押します。そしたら Pull Request が作成されます。

実際にPull Request が以下のように作成されます。

github.com

GitHub Theme

GitHub 純正の VSCode の Theme。 見やすい気がするので使ってみてます。

marketplace.visualstudio.com

まとめ

GitHubマイクロソフトの傘下になってからというもの VSCode 関連のインテグレートの進化が凄すぎて、いろいろついていけてませんでしたが、VSCodeGitHub をベッタベタに密結合させると VSCode が優秀な Github クライアントになるので、今後もいろいろ試してみようと思います。

VSCode の Column Select Mode を Off にする

サマリ

タイトルの通りです。 いつからか、VSCode でマウスを使って範囲選択を行うときに選択された範囲が Column Select Mode の状態になってしまってました。 意図してそうしていたならともかく意図せずに On になっていたので VSCode が急に使いづらくなってました。

Column Select Mode

こういうやつ。

便利だけど、マウスカーソルでの選択にも影響出るとは知らずにびっくりしました。

Off の仕方

メニューバーにある Selection から Column Select Mode を Off にします。 Cmd + Shift + * でも On/Off を変更することができます。

Local での DynamoDB の動作確認方法

サマリ

DynamoDB を使った機能を Local で動作確認したいケースでは以下の2つのツールが使えそう。

  1. DynamoDB Local
  2. ddbcli

DynamoDB Local

ブラウザでGUIとして操作できる。

Docker image があるので落としてくればそのまま使える。

hub.docker.com

ddbcli

ターミナル SQL ライクに使える

github.com

qiita.com

進捗を無にする方法

あれこれコードを書いてて、結局その差分が全然意味をなさなくて、自分の差分を無に返したい時がありますね。 僕はあります。

そんな時は

$ git checkout .

// or

$ git restore .

を使います。

これで自分の進捗を無にすることできます。 間違っても実装途中で使わないでくださいね。

VSCode で Go の自動補完に gopls + TabNine を使ってみる

Summary

qiita.com

上記のエントリを読んで試しに、VSCode + TabNine の組み合わせをセットアップしたら gopls を使っているにも関わらず、Go の自動補完が爆速になって開発者体験がめちゃくちゃ向上したのでその手順を記載しています。
と言うのも、元々 Intelij を使っていたのですが、gopls の開発活発化に合わせて、ここ1年くらいは VSCode + gopls の環境で作業をしていました。ただ、どうしても VSCode と gopls をセットで使う場合に、langage server との通信ラグがコードの補完と微妙にあってなく、僕が思ってる速度でコードが書けないと言う課題がありました。
そんな中使い続けてたら Go を暗記し始めたので、実質補完いらないみたいな世界線に最近片足突っ込み始めてますが笑

まぁめちゃくちゃPCのメモリを食うのでまぁファンが鳴り止まない、と言う自体もあって何かいいツールはないものか(ここで Intelijにまた戻るのか?)探し続けてたところ、TabNine を知りました。

TabNine とは?

www.tabnine.com

tkrel.com

僕はこんな機会があるまで全然知らなかったんですが、 深層学習を用いることで、より精度の高い入力補完を実現 するツールのようです。
(すごい世の中ですね。)

VSCode のセットアップ

gopls

Goを使う場合は基本的には gopls がついてくるので、特に何かをインストールする必要はありません。
最新、と言うか master の gopls を使いたい場合は go get -u golang.org/x/tools/gopls で取得します。

VSCodesetting.json は以下のようにします。

"format": false,              
"autoComplete": true,         
"rename": true,               
"goToDefinition": true,       
"hover": true,                
"signatureHelp": true,        
"goToTypeDefinition": true,   
"documentSymbols": true,      
"workspaceSymbols": true,     
"findReferences": true,       
"diagnostics": true,          
"documentLink": true,         
"goToImplementation": true,   

余談ですが、最近 gofmt を off った状態で使用しています。どうやら VSCode 側の format on save (go.formatTool で指定したツール) とバッティングせずに動作が少し改善?されるような気がしてます。
詳しいところは追っかけてませんが、gofmt を true にしていたときは大きなファイルに変更を加えると VSCode の fmt のプロセスがなかなか終わらずファイルが save されない、と言う状況を起こしてしまっていました。 gofmt を off って状態でも VSCode 側での goimports に任せるようにした場合、特に fmt や import で困ることもなかったので、結果としては保存時のストレスは最近の作業に限って言うとなくなりました。

TabNine

Setup

参考にしたエントリに記載されているように TabNine のプラグインをインストールします。
プラグインを入れたらソースコードのどこかに TabNine::config を打ちます。そうするとデフォルトブラウザ TabNine の設定画面が開きます。 ブラウザが開かれるとわかりますが、 http://127.0.0.1:5555/{$任意の文字列} と言うURLになっています。このURLはユーザーごとに違うのかまではわかりません。僕の環境では払い出されるURLは毎回同じでした。

エントリには設定方法が記載されていますが、202007 時点では v2.8 系が出ており、これは特に設定等もいらずに TabNine::config で設定を開いたと同時にモデルのDLが始まっていました。

Local or Cloud

TabNine には Local モードと Cloud モードがあります。Cloud モードはクラウド上にある TabNine のサーバー上でコードの自動補完を検査するようです。これは意図せずコードが外部に流出してしまう可能性があるので業務レベルで使いたい場合は Local 一択でしょう。

ちなみにクラウドの機能をフルで使うには有償版に乗り換えないといけないっぽいです。セットアップ時はメールアドレスを入力して送信するだけでしたが。。。(ベータ版はもう終わったのだろうか。)

www.tabnine.com

設定画面に activation するための key を入力するところがありましたし、Cloud 版を試してみたい方は有償版に切り替えて使ってみて欲しいです。

気になる点

深層学習による、コードの補完サポート、と言う立ち位置なので、独自のパッケージ構成や変数定義については完全には追従してません。特にローカル版においては。
頻出パターンなどを含めて学習したモデルを使って自動補完の候補を出力しているので、プライベートなリポジトリの結果が反映されないのも当たり前といえば当たり前ですが。。。 ただ、多少のシグネチャの揺れは合ってもある程度実用に耐えそうな感覚はあります。これから使い倒していくうちに見方が変わるかもしれません笑

まとめ

思いの外開発者体験が向上したので興味がある方は是非1度使ってみてください。
正直まだ使い始めたばかりなので、しんどいところを経験してないですが、もし何かあればまたアップデートをかけようと思います。

VSCodeでMySQLを使用するためのプラグイン

Overview

VSCodeMySQL を使うときのプラグインについて記載します。

主に達成したいことは以下です。

  • クエリの自動補完

インストールしたプラグイン

以下の2つのうちどちらかを入れておけば問題なさそうです。

marketplace.visualstudio.com

marketplace.visualstudio.com

注意点はくれぐれも *.sql ファイルで発火する SQLServer はインストールしないことです。これは Azure 向けのエクステンションであるので MySQLシンタックスが使えないことがあります。
ずっとおかしいなぁなんでエラー出るんだろうと思ってましたが、後から description 読んでそりゃそうだろ...みたいな気持ちになりました。

追記

20220820

フォーマットをかけて欲しくない + 簡単な MySQL の補完だけしてほしい、という要件であればいいので、以下の Extention が特に変なことをしない、という点で良さそうでした。

marketplace.visualstudio.com

20220906

もうこれでいいんじゃないか説があります(上記の全ての extention がフォーマットかかってしまう)

marketplace.visualstudio.com

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 コマンドが動いたのでこのエントリはこれでおしまい。