Code for final

ふぁいなる向けのコード置き場です。すでにコードじゃないこともいっぱい。

Windows10にDocker Desktop for WindowsをいれてLinuxコンテナで動かす手順(実践編)

Dockerの導入について以下の記事で書きましたが、ただwebサーバーを立てただけで、コンテンツを更新したりする手順とかわからなく、 このままだと実務で使うときに苦労すると思ったので実務を想定して必要そうな知識をまとめたいと思います。
ここでいう実務は開発、テストを想定しています。本番で運用するためにはもっといろいろと知識が必要ですのでご注意を。

final.hateblo.jp

コンテンツを適用する方法は2つある

基本編ではwebサーバーを立てて"It Works!"が出て満足していましたが、実務ではコンテンツをサーバに配置する必要があります。
Dockerではその手順として2つあります。

  • コンテナ内のファイルを差し替える
  • ホストのフォルダをコンテナ内のフォルダとリンクする

後者だけ覚えておけばなんとかなりそうな気もしますが、テストとかだとコンテンツを配るのが面倒なときとかに使えそうな気はしますので両方説明します。

コンテナ内のファイルを差し替える

試しにapache webサーバーのindex.htmlを書き換えてみます。

まずコンテナ同士が別々に動作していることがわかるようにもう一個apacheのサーバを立てます。 名前とポートを変えれば何個でも作成可能です。

> docker run -d -p 8080:80 --name httpd2 httpd

"localhost:8080"でアクセスしたら"It works!"と表示されると思います。

ではこのhttpd2の方のLinux環境に入るには"docker exec"コマンドをたたいてください。 httpd2のところは入りたいコンテナ名を指定するだけであとはおまじないみたいなものです。

>docker exec -it httpd2 bash

すると以下のようになると思います。(@の右はコンテナIDでコンテナ作成時にランダムで生成されるので環境によって異なります)
sshでつないだときと同様にLinuxコマンドが実行できます。

root@4d11a0179bc4:/usr/local/apache2#

なのでapacheのindex.htmlファイルはhtdocsの下にあるので以下のコマンドで確認できます。

root@4d11a0179bc4:/usr/local/apache2# cd htdocs
root@4d11a0179bc4:/usr/local/apache2/htdocs# ls
index.html
root@4d11a0179bc4:/usr/local/apache2/htdocs# cat index.html
<html><body><h1>It works! </h1></body></html>

これを書き換えればいいのですが、viとかvimとか入っていないので、Windows環境から転送するしかないです。
Windows環境に戻るために"exit"をたたきます。そうするとWindowsに戻ります。

以下のコマンドを実行してワークディレクトリを作っておきます。

>cd c:\
>mkdir docker_work
>cd docker_work

まずは書き換えるためにコンテナ(Linux)内からWindowsにindex.htmlを持ってきます。 以下のコマンドを叩いて取得します。 "4d11a0179bc4"は各自のものに変えてください。先程のdocker execのとこからコピーすると確実かと思います。

>docker cp 4d11a0179bc4:/usr/local/apache2/htdocs .\htdocs

"docker cp"コマンドでホスト(Windows)とコンテナ(Linux)間のファイルやり取りができます。
cpコマンド同様、コピー元 コピー先で指定します。 コピー元のコンテナは"コンテナid:Linuxファイルパス"で指定します。
注意すべきところはコンテナ側のパスを指定するときはコンテナ名(httpd2)ではなく、コンテナIDを指定します。 コンテナIDは"docker exec"で接続するか"docker ps"で確認できます。

これで"c:\docker_work"にhtdocsフォルダができ、index.htmlが取得されたと思います。
index.htmlを自由に編集してください。

編集が終わったら次は以下のコマンドでコンテナ側にコピーします。
さっきと逆でコピー先がコンテナになります。

>docker cp .\htdocs 4d11a0179bc4:/usr/local/apache2

これで"localhost:8080"にアクセスすると表示される内容が変わったと思います。
"localhost"にアクセスしても"It works!"のままだと思います。
これでコンテナが別々の環境で動作していることがわかったと思います。 "localhost"を変えたい場合はhttpdのコンテナを同様に書き換えてみてください。

コンテナの状態をイメージとして保存する

コンテナをイメージとして保存することでいつでも"docker run"コマンドでコンテナを生成することができるようになります。
さきほどの"localhost:8080"の環境をイメージとして保存したいと思います。

httpd2の環境を保存するために以下の"docker commit"コマンドで状態を保存します。

>docker commit httpd2 httpdex:1.0

このコマンドの意味はhttpd2環境をhttpdexというイメージ名のタグ1.0で保存するという意味です。
以下のコマンドを実行して3台目のサーバを立てます。イメージにはいまほど作成した"httpdex:1.0"を指定します。

>docker run -d -p 8088:80 --name httpd3 httpdex:1.0

これで"localhost:8088"にアクセスするとhttpd2のコンテナ("localhost:8080")と同じ内容が表示されると思います。
これで"localhost:8080"の内容がイメージとして保存されてたということが確認できました。

ホストのフォルダをコンテナ内のフォルダとリンクする

さきほどのでコンテナ内のファイルを書き換えることができたと思いますが、これだと更新する度に書き換える必要があって、開発中は現実的ではないと思います。
コンテナ(Linux)がホスト(Windows)のフォルダを参照してくれるように設定することができます。

次に以下のコマンドを実行してさきほど保存したイメージ"httpdex:1.0"をベースに4台目のサーバを立てます。 ※実行時に共有フォルダに追加するかと聞かれると思いますが、”Share it”を選択してください。(キャンセルすると失敗します)

>docker run -v c:\docker_work\htdocs:/usr/local/apache2/htdocs  -d -p 8888:80 --name httpd4 httpdex:1.0

"localhost:8888"でアクセスするとhttpd3と同じ結果になると思いますが、ここで"c:\docker_work\htdocs"にあるindex.htmlを編集してください。
再度アクセスすると変更した内容が反映されていると思います。ほかのサーバーは変更されてないのも確認できると思います。
このように"docker run"実行時に"-v ホストのフォルダ(Windows):コンテナのパス(Linux)"を指定することでリンクできます。
ちなみに-vを複数個指定することもできるみたいです。

これで開発に耐えうる環境が構築できますね。

カスタマイズしたコンテナイメージを配布する

上記でカスタマイズしたコンテナイメージをほかの人にテストしてもらう場合、渡す必要があります。
その場合はファイルとして出力できます。

まず以下のコマンドを実行してコンテナイメージを確認しましょう。

>docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
httpdex             1.0                 379506f88e8f        21 hours ago        166MB
httpd               latest              b2c2ab6dcf2e        11 days ago         166MB

保存したイメージをファイルに出力するには"docker save"コマンドを実行します。 以下のコマンドで"httpdex:1.0"のイメージを出力します。

>docker save -o httpdex-1.0.tar httpdex:1.0

"httpdex-1.0.tar"が出力されますのでこのファイルをほかの人に渡して"docker load"コマンドを実行してイメージファイルを取り込んでもらいます。

>docker load -i httpdex-1.0.tar

あとはdocker runコマンドでイメージ名"httpdex:1.0"を指定してもらえばほかの人の端末にも同じ環境が構築されます。

複数のコンテナを連携したサービスを構築する

以下にまとめました。

final.hateblo.jp

最後に

ここに書いたのは基本的なことなので詳細は必要に応じて調べてみてください。
でわ、素敵なDockerライフを。

Windows10にDocker Desktop for WindowsをいれてLinuxコンテナで動かす手順(基本編)

Dockerについて以前調べたときに以下の記事を書いたのですが、その後時代は進んだようで、2020年5月現在でもっと簡単に構築できるようになっていたのでメモしておきます。

final.hateblo.jp

Dockerに関する誤解(Windows版だとLinuxのインストールが必要?)

まずわたしだけかもですが、Windows版のDockerを入れるとWindowsで動くので、Linux環境で動かすにはdockerでLinuxOSを入れて、LinuxOS内にdockerをいれてみたいな手順が必要で手間がかかると思っており、 Windows版を敬遠していましたが、それは大きな誤解でした。
その答えはWindows版をインストールしたらわかりました。Windows版のインストールはHyper-Vを有効にしておくことが必須なのですが、それはなぜかというとWindows版のインストール時にHyper-Vに"DockerDesktopVM"というDockerを動かすためだけのLinux環境が作成されます。
なのでWindowsコマンドプロンプトからdockerコマンドをたたいたら、実際は内部で動いてるLinuxの環境で実行されるというわけです。
というわけなのでLinux環境で動かしたい方も安心してWindows版を使ってください。(VirtualBoxCentOSを入れるより簡単で便利です)

Hyper-VはHomeエディションでは使えないのでWindows版は使えない?

Hyper-VはHomeエディションでは使えないことは有名な話だと思いますが、次のWindows10 2004(2020/05/04時点では未リリース)から"WSL2(Windows Subsystem for Linux(WSL) 2)"という機能(Hyper-Vと似たようなもの)がリリースされ、これを使うことでDocker Desktopを動作させることができるみたいです。気になる方はググってみてください。

Dockerとは?

Dockerに興味があるひとがこの記事にたどり着いていると思うので説明不要だと思いますが、簡単に言えば仮想サーバ構築ツールです。
VMと異なるのはサーバごとにOSのインストールは不要で、1つのサーバ上に複数のサーバの構築ができます。
構築したサーバはイメージ化して配布できるので誰がやっても同じ環境が構築できます。
また、各種サーバアプリ(ApacheMySQLなど)のイメージが公開されており、コマンド1つで構築可能です。
僕はインフラ周りはあまりやらないのですが、開発環境やテスト環境構築とかで使えると思います。

www.docker.com

それでは以下に手順を記載します。

Hyper-Vを有効化

Hyper-Vはデフォルトでは有効になっていません。
なのでPowerShellを管理者権限で起動して以下のコマンドを実行します。

Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All

インストールが終わったら再起動が促されます。手順に不安がある方は以下を参照してください。

docs.microsoft.com

Docker Desktop for Windowsをダウンロード

Docker公式サイトからDockerDesktop for Windowsをダウンロードします。
以下のサイトの"Docker Desktop"の"Download for Windows"をクリックするとダウンロードが始まります。 ファイルサイズは1GB近くあります。

www.docker.com

Docker Desktop for Windowsをインストール

ダウンロードした"Docker Desktop Installer.exe"を実行して、OKを押して次へ進むだけでOKです。
途中、"Use Windows containers instead of Linux containers (this can be changed after installation)"の チェックがOFFであることを確認してください。(デフォルトでOFFなので何もしなくてよいですが) これは訳すと"Linuxコンテナーの代わりにWindowsコンテナーを使用する"なのでチェックがOFFの場合Linuxコンテナで動作します。インストール後に切り替えも可能です。
インストールが終わると再起動が促されます。

Docker用の仮想環境がはいってることを確認 (この手順は省略可)

Windowsの再起動後、検索ボックスに"hyper-v"といれて"Hyper-V マネージャー"を立ち上げると以下のように "DockerDesktopVM"という仮想環境が構築されていることが確認できます。これがDockerを動かすためのLinux環境の正体です。

f:id:finalstream:20200503181903p:plain

Dockerコマンドを実行する

PowerShellを立ち上げて"docker version"をたたいて、バージョンが表示されればインストール成功です。
コマンドプロンプトでもOKですが、PowerShellのほうがシャットダウンしてもコマンドの履歴が残るので便利です。

> docker version
Client: Docker Engine - Community
 Version:           19.03.8
 API version:       1.40
 Go version:        go1.12.17
 Git commit:        afacb8b
 Built:             Wed Mar 11 01:23:10 2020
 OS/Arch:           windows/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          19.03.8
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.12.17
  Git commit:       afacb8b
  Built:            Wed Mar 11 01:29:16 2020
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          v1.2.13
  GitCommit:        7ad184331fa3e55e52b890ea95e65ba581ae3429
 runc:
  Version:          1.0.0-rc10
  GitCommit:        dc9208a3303feef5b3839f4323d9beb36df0a9dd
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683

DockerでWEBサーバを構築

上記までの手順ではDockerのエンジンだけインストールされているのでこっから本領発揮のとこです。
試しにapache webサーバを構築してみます。 Dockerは各種アプリのイメージが公式的に公開されており、そのイメージをダウンロードしてローカルサーバで動かす仕組みとなってます。
どんなイメージがあるかは以下のサイトで確認できると思いますが、RedminePostgreSQL、Jenkinsなどわりとなんでもあります。

hub.docker.com

なので以下の"docker run"コマンドを流すだけで、apche webサーバーの構築ができてしまいます。
構築した環境はコンテナと呼びます。

> docker run -d -p 80:80 --name httpd httpd

オプションの意味を簡単に解説すると以下になります。

  • "-d"はバックグラウンドで動作させる(指定しないとコンソールが持っていかれる)
  • "-p 80:80"(ホスト:コンテナ)はポート転送設定(試しに8080:80にするとlocalhost:8080でアクセスできる)
  • "--name http"は名前を"httpd"にする。(指定しないとランダムでヘンテコな名前が命名される)
  • 最後の"httpd"はDocker Hubで公開されているイメージ名

起動したかは以下の"docker ps"コマンドで、httpdがいればOKです。

>docker ps
CONTAINER ID        IMAGE               COMMAND              CREATED             STATUS              PORTS                NAMES
1b38ad530ec1        httpd               "httpd-foreground"   2 minutes ago       Up 2 minutes        0.0.0.0:80->80/tcp   httpd

WEBサーバの起動を確認

Windowsからブラウザを起動して、"localhost"をアドレスバーにいれてたたくと さみしいapacheの初期画面がでれば起動しているということです。

f:id:finalstream:20200503183816p:plain

DockerをGUIで操作

Windows版ではDockerアプリのDashboardを開けば画面で確認できます。(タスクトレイのクジラのアイコンを右クリックでDashboardを選択)
緑になっていれば動いています。ここから停止とか削除もできます。便利ですね。

f:id:finalstream:20200503183452p:plain

さらにhttpdを選択すれば詳細が確認でき、アプリごとのログを確認できます。超便利。

f:id:finalstream:20200503190510p:plain

最後に

以前VirtualBoxを使った構築に比べたらだいぶ簡単に構築できました。マシンのスペックによりますが、30min以内でできるんじゃないでしょうか。
まだまだ奥が深いDockerですが、ここまでなんとなくDockerについてさらに手軽になった感じが伝わったかと思います。
ただ、実際の業務で使用するにはまだまだ必要な知識が足りないので、あと実践編としてまとめたいと思います。
では素敵なDockerライフを。

TypeScriptは難しくない。JavaScriptをやったことあればTypeScriptでシステム開発はすぐできる。メリットだらけなのでやったほうがいい。

ついこないだまでTypeScriptでシステム開発をってやってみたいけど 新しく覚えるの大変だろうな、覚えること多いんだろうなーって思って JavaScriptに逃げていました。
でも、思いきって今回仕事でTypeScriptを使って、システムのリリースまで終わったいまでは 絶対JavaScriptより、TypeScriptがいいって思います。

あとで詳しく書いていますが、TypeScriptでシステム開発しようと思って未経験者しか集まらなくても、 JavaScriptをやったことあれば、以下の2つだけ伝えればTypeScriptでシステム開発できますし、メリットだらけなのでやったほうがいいです。
現に今回やったシステム開発(20名くらい)で誰一人TypeScriptやったことあるひとはいませんでしたが、TypeScriptで開発できたので実証済みです。

  • 型推論できるものは型は書かない。わからないひとはエラーになったら型を書くこと。
  • 変数はまずconstで宣言する。変更する必要があるものはlet。varは使用禁止。わからないひとはconstでエラーになったらletにする。

TypeScriptが何者かご存じない方は、以下を見てもらえればわかりますが、 TypeScriptで書いたコードはビルドすることでJavaScriptに変換され、ブラウザで実行されます。
Microsoftが開発したものなので将来的にも安心して使えますし、導入するときに顧客に説明するときもMicrosoftが作ったものと言えばすんなり通るでしょう。

ja.wikipedia.org

わたしがTypeScriptを誤解していた点、良いと思う点についてまとめたいと思います。

誤解していた点

覚えないといけないことが多そう

コードを書くという点でいえばぜんぜん覚えることないです。
より便利にコーディングするために知ってたほうがいいことはいくつかありますが。
TypeScriptはJavaScriptに型が追加になったものと認識で問題ないとわたしは思います。
その型もプリミティブ型(基本の型)でいえばstring, number, booleanくらいしかありません。あと使うのは自分で作ったクラスです。
あとは変数宣言にはvarを使わずconstを使うくらいですかね。 また、細かい点はコードが間違っているとエディタが警告してくれるので始める前に学習しなくても自然と身につきます。

型を書かないといけないので逆にコード量が増えて大変そう

TypeScriptは型が追加になるってことくらいは知っているひとは多いと思います。
C#やったことあるひとならわかると思いますが、型推論があるのでそんなに気にしなくていいです。
型推論がわからないひとは以下のコードを見てもらえばと思います。
型をつける、つけないの判断できないのではないかと不安に思うひともいると思いますが、 ご安心ください。 つけないといけない場合はビルドエラーになるのでわかります。VSCodeが赤線を引いてくれます。

const id = ""; // string型と推論できるので型の記載は不要です。
const id; // 初期値から型推論できないので型が必要です。ビルドエラーになります。

書いたコードを見直しましたが、型を書いてたのはメソッドの引数と戻り値の宣言と独自のクラスにキャストするときくらいでした。
メソッドの引数と戻り値(ある場合)は必ず書いたほうがいいです。それがTypeScriptのいいところですから。
その理由は後述します。

自分だけコーディングできてもチーム全員できないとチーム開発では使えないのでは?

今回のプロジェクトでは20名ほどコーダーがいましたが、 誰一人TypeScriptを使ったことあるひとがいませんでした。存在すらしらなかった人が多かったです。
ただ、JavaScriptをやったことあるといったひとでした。
このご時世、JavaScriptをやったことないひとは新人くらいだと思います。
JavaScriptさえ知っていればチーム開発でもTypeScriptは全然使えます。
以下の3点だけ説明すればOKだとわたしは思います。
実際、今回の開発もこれでうまくいきました。

  • 型推論できるものは型は書かない。わからないひとはエラーになったら型を書くこと。
  • 変数はまずconstで宣言する。変更する必要があるものはlet。varは使用禁止。わからないひとはconstでエラーになったらletにする。
  • エディタ上で赤い線が出ているところは必ず修正する。(当たり前ですけど守られていないことがありました)

守らないひとがいてバラバラになるのでは?と危惧されると思いますが、エディタの設定で矯正できますし、 最終的にビルドのときにエラーになるのでわかります。

ビルド(コンパイル)環境を構築するのがめんどそう

JavaScriptはビルドする必要がないので、手軽さという点ではJavaScriptよりは劣ると思っていました。
これがわたしが一番敬遠する理由でした。
コマンドでビルドする仕掛けをバッチ処理で作る必要があるのかと思っていました。
ただ、Vue CLIを使うことでまったくビルドしている感じなく、 JavaScript同様に使えるので杞憂だったということがわかりました。
今回はVueだったのでVue CLIでしたが、ほかの環境でもきっと同じだと思います。

ビルドしたものを動かすからデバッグができないのでは?

デバッグはtsファイルにブレークポイントをつけて普通にできますのでご安心を。
デバッグのテクニックは後日記事を書きたいと思います。

良い点

タイプミスに早期に気づける

これが一番の魅力だと思います。IDEが発展してきてインテリセンスなどで だいぶタイプミスによるバグを軽減することができるようになりましたが、 完全にゼロにすることはできません。
TypeScriptではビルド時にチェックはもちろん、VSCodeだとエディタ上で 赤い線で警告することもできるので効率よくコーディングできます。

const userid = "a";
// 宣言が見えないくらい間があいている
alert(user_id); // ビルドエラーになる。user_idという変数は宣言されていないため

想定と違う型の値が入ることがない

JavaScriptだと型がないのでどんな値でも入るので 間違って違う型の値が入ってる可能性があるかもと心配することがあるかもしれませんが、 TypeScriptでは型があるので型に当てはまらないものは入りません。
また、使う機会は局所的ですが、any型というなんでも入る型もあります。

let value = "0"; // 型推論で文字列型になる。
value = 1; // 数値型はいれることができない。

メソッドに渡しているものが間違っていると警告してくれる

メソッドの引数と戻り値には必ず型を定義しますので、 間違った型の変数を渡したら赤で警告がでるのでコーディングミスが事前に防げます。
JavaScriptだと動かしてエラーになるまで気づけません。

function main() {
  this.add(1)
}

function addPrefix(value: string) :string {
  return "prefix" + string;
}

変数が変わってないことを保証してくれる

TypeScriptでは変数をconstで宣言することをおすすめします。
constは一般的に定数で使うキーワードですが、TypeScriptでは 一度いれたらインスタンスを変更できない変数として使います。
変更しようとしたら警告してくれるので間違いに気づけます。
変数って意外と一回入れたら変更しないものです。
今回開発したコードを見直しましたが、ほとんどconstでいけてました。
letを使ってたのはループ内変数くらいですね。
ちなみにconstでarrayを宣言してpushしてもエラーにはなりません。
インスタンスを変更していないので。

const numbers = [];
numbers.push(1); // ○ エラーにはならない。インスタンスを変更していないから。
numbers = []; // ✕ エラーになる

for (let i = 0; i < array.length; i++) { 
  // forで回すときはletを使う
}

メソッドの処理でnullやundefifnedチェック処理が不要になる

JavaScriptだとundefinedやnullが入ってこないかチェックする必要があったりしますが、 TypeScriptではnullとundefinedを型として扱うことができるので、 チェックする必要がなくコードがスッキリします。(HTMLとの境界のメソッドでは一部例外もありますが) 誤っていれたらエディタで赤い線が出るのでわかりやすいです。
もちろんnullを使いたいときは使うこともできます。

const value = ""; // string
const value :string = null; // ビルドエラーになる
const value :string | null = null; // nullをいれることができる

map型がある

システム開発ではよくmap型を使います。
JavaScriptにはmap型がなく、代替としてobjectをmapとして使ったりしますが、 TypeScriptでは標準でmap型があるので非常に便利です。

const idMap = new Map<string, number>();
idMap.set("a", 1);
idMap.set("b", 2);
idMap.forEach((value, key)=>{
  console.log(value); // mapを回すことも可能
});

クラスが使える

クラスもシステム開発では必須といっていいと思います。
データを定義するのに使います。
特に継承をうまく使って共通化したりすれば、品質も生産性もあがります。

export default class Home extends Base {

}

というようにいいことしかないのでこれからWEBシステムを開発するひとがいたら JavaScriptではなく、ぜひTypeScriptで開発してほしいと思います。