Docker for Windowのインストールから利用までの(ほぼ)CUI手順

# 普通にDocker for Windowsのインストーラ使うのが良い
Scoopを整理した時にDockerをアンインストールしてDocker for Windowsで入れなおしてみたら普通に使いやすかった。宗教上の理由でCUIしか触れない人くらい意味のない記事になっているが、いつかどこかで加工して再利用するかも知れないのでまだ残しとくのである。

# Dockerって何が嬉しいの？
百聞は一見に如かず、百見は一触に如かず。
という事で触れてみて欲しい。
# 概念とかは置いといてまずは触ってみる
WindowsでDockerを取り敢えず触ってみようじゃないかという人向けに、**理解は後工程でいい**というコンセプトでこの記事を書いている。プロキシ環境を想定している。
# 目次
- 1　PowerShellのプロキシ設定
- 2　scoopのインストール
- 3　docker-machineのインストール
- 4　docker-machineへのプロキシ設定
- 5　Docker HubからCentOSイメージを取得
- 6　コンテナの起動
- 7　プライベートレジストリの構築
- 8　イメージ作成とプライベートレジストリへのpush
- 9　プライベートレジストリからのpull

こんな感じで、説明を最小限に抑えただただ手順を羅列していく。

# 前提条件
- OSはWindows7以降。
- VirtualBoxが必要なのでなければ[ここ](https://www.virtualbox.org/)からインストールしておく。
- 仮想化支援機能を有効にする。（進めていってdocker-machineの作成時にエラーが出てからでも良い）
- PowerShellのバージョンは3以降が必要。

`powershell $PSVersionTable`で確認してPSVersionが2.xの場合はPowerShellのバージョンアップを先にする必要がある。

筆者はクリーンインストールしたWindows7 SP1で手順を確認しながらこの記事を書いているため、PowerShell更新で要求された.NETのインストールも行った。
# まずはPowerShellのプロキシ設定

PowerShellを管理者権限で起動。
ここではコマンドプロンプトから起動する。まずはこいつが認証プロキシを潜れるようにする。

```
C:\>@powershell -NoProfile -ExecutionPolicy unrestricted -Command "Start-Process powershell.exe -Verb runas"
```

profile.ps1を作成する。
**※既にprofile.ps1を作っている人は`New-Item~`をすると消えるので注意。**

```
PS C:\> New-Item -path $profile -type file -force
```
メモ帳で開く。

```
PS C:\> notepad $profile
```

Microsoft.PowerShell_profile.ps1を編集する。プロキシの設定を書こう。yourusernameとyourpasswordとyourproxyhostとポート番号を編集して保存する。
その他環境に合わせて。**実はここでno_proxyの設定が後々重要になってくる。**

認証ありProxy

```powershell:Microsoft.PowerShell_profile.ps1
# Encoding::Shift-JIS
$user = "yourusername"
$password = "yourpassword"
$proxyhost = "yourproxyhost:8080"
$proxyaddress = "http://$($proxyhost)/"
$env:http_proxy = "http://$($user):$($password)@$($proxyhost)"
$env:https_proxy = "http://$($user):$($password)@$($proxyhost)"
$env:no_proxy = "192.168.99.100"
$env:ftp_proxy = "http://$($user):$($password)@$($proxyhost)"
$password_secure = ConvertTo-SecureString $password -AsPlainText -Force
$creds = New-Object System.Management.Automation.PSCredential $user, $password_secure
$proxy = New-Object System.Net.WebProxy $proxyaddress
$proxy.Credentials = $creds
[System.Net.WebRequest]::DefaultWebProxy = $proxy
echo 'Set-Proxy OK.'
```

認証なしProxy

```powershell:Microsoft.PowerShell_profile.ps1
# Encoding::Shift-JIS
$proxyhost = "yourproxyhost:8080"
$proxyaddress = "http://$($proxyhost)/"
$env:http_proxy = "http://$($proxyhost)"
$env:https_proxy = "http://$($proxyhost)"
$env:no_proxy = "192.168.99.100"
$env:ftp_proxy = "http://$($proxyhost)"
$proxy = New-Object System.Net.WebProxy $proxyaddress
$proxy.Credentials = $creds
[System.Net.WebRequest]::DefaultWebProxy = $proxy
echo 'Set-Proxy OK.'
```
スクリプトの実行を許可する。

```
Set-ExecutionPolicy RemoteSigned
```
実行ポリシーの変更 → Y

```
実行ポリシーの変更
実行ポリシーは、信頼されていないスクリプトからの保護に役立ちます。実行ポリシーを変更すると、about_Execution_Policies のヘルプ トピックで説明されているセキュリティ上の危険にさらされる可能性があります。実行ポリシーを変更しますか?
[Y] はい(Y)  [N] いいえ(N)  [S] 中断(S)  [?] ヘルプ (既定値は "Y"): Y
```
スクリプトを走らせる。

```
.$profile
```
`Set-Proxy OK.`と出る。
これで毎回プロキシ設定がされた状態でPowerShellが立ち上がる。

# scoopをインストールする
[scoop](https://scoop.sh/)はWindows用のyumみたいな奴だ。

```
iex (new-object net.webclient).downloadstring('https://get.scoop.sh')
```

# docker-machineをインストール
scoopのbucket追加に必要なためgitをインストールしてextras bucketを追加してdockerをインストールするという手順になる。

```
// Gitをインストール
PS C:\> scoop install git

// extras bucketを追加
PS C:\> scoop bucket add extras

// インストール
PS C:\> scoop install docker docker-compose docker-machine
```
# docker-machineの作成とプロキシ設定
PowerShellに設定してあるプロキシ情報を使ってdocker-machineを作成する。docker-machineはdockerのインストールされた[Tiny Core Linux](http://tinycorelinux.net/)だ。

生成コマンドは以下。defaultというdocker-machineを作成している。UACが有効だと何回か許可を求めるダイアログが出てくるが、気付きにくいので注意。

```
PS C:\> docker-machine create --engine-env  http_proxy=$env:http_proxy --engine-env https_proxy=$env:https_proxy default
```
これで作成できたら以下の様にしてdocker-machineに繋いでみよう。

```
PS C:\> docker-machine ssh
```
これで`docker@default~$`といった具合にプロンプトが表示されれば話は早いのだが、ASCII エスケープコードをそのまま表示しているかも知れない。

```sh:こんな感じで
[1;32mdocker@default[0m:[1;34m~[0m$ 
```

自分のマシンでは色が解釈されて表示されるのだが、**実はどうやったのか忘れた。(誰か教えて)**
というわけで今回はcmderを使う。

```
PS > scoop install cmder
PS > cmder
```
まあcmder使いやすいから「今回は」って話じゃなくずっと使えるんだけど。どうやったのか、わかんなくなったのが気持ち悪いだけで。
# Docker HubからCentOSイメージを取得
ここから先、`$`のプロンプトはdocker-machine内でのコマンドを表す。
どこで入力しているコマンドなのかはプロンプトで判別して頂きたい。

|プロンプト|対象|
|---|---|
|>|PowerShell|
|$|docker-machine|
|#|コンテナ内|

```
$ docker pull centos
```

これが取れればプロキシの設定などは上手く行っている。

# コンテナの起動
```
$ docker run -it --name hoge centos
```

これでコンテナに接続できた。試しに`cat /etc/redhat-release`とかコマンドを叩いて見ると、バージョンが表示されるはずである。

コンテナを終了せず抜けるには**Ctrlを押しながらpとq**で抜けてこれる。**Ctrl+d**だとコンテナを終了する。

今回は終了させずに抜けて、```docker ps```としてみて欲しい。今作ったhogeコンテナがあるはずだ。

```
$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
ac3e84fba733        centos              "/bin/bash"         3 minutes ago       Up 3 minutes                            hoge
```
では```docker stop hoge```で停止させよう。
```docker ps -a```とすると動いていないコンテナも見れる。Exitedとなっているはずである。

```
$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                        PORTS               NAMES
ac3e84fba733        centos              "/bin/bash"         4 minutes ago       Exited (137) 44 seconds ago                       hoge
```
もう一度このコンテナを起動してみよう。

```
$ docker start hoge
```
稼働中のコンテナにはattachでアタッチする。

```
$ docker attach hoge
```
今度は`exit`と打って抜ける。```docker ps -a```で見るとコンテナは停止している。

# プライベートレジストリの構築
dockerのイメージはレジストリに登録して共有できる。そのdockerのレジストリもコンテナを使う。

業務で使うにはプライベートレジストリを用意したい所である。実際にはみんながアクセスできるlinuxサーバーに構築するところなのだが、今回はローカルで立ててみる。

registryというイメージを使う。pullは省略できる。無ければ勝手に取ってくるからだ。よってrunでいきなりコンテナを起動させよう。

```
$ docker run -d -p 5000:5000 registry
```
ポートフォワーディングの関係でパラメータが増えているが、今は説明を省く。
これでプライベートレジストリが起動した。

# イメージ作成とプライベートレジストリへのpush
折角なのでhogeコンテナにちょっといたずらしよう。
今hogeは止まっているので'run -it'で接続する。

```
$ docker run -it hoge
```
適当なテキストファイルを作ってコンテナを止める。

```
# echo helohelo > /opt/f.txt
# exit
```
commitコマンドでイメージにする。この時に登録するレジストリのホストとポートも書いておく。

```
$ docker commit hoge localhost:5000/fuga
```
pushでプッシュ。実に分かりやすい。

```
$ docker push localhost:5000/fuga
```
これでレジストリにhogeコンテナのイメージが登録された。

# プライベートレジストリからのpull
確認の為にregistry以外のイメージを全部消しておこう。

```
$ docker images
```
これでイメージが列挙される。イメージの削除はrmiを使う。

```
$ docker images

REPOSITORY            TAG                 IMAGE ID            CREATED             SIZE
localhost:5000/fuga   latest              43821587a2f1        10 minutes ago      202MB

$ docker rmi 43821587a2f1        
```
centosも新しく作られているlocalhost:5000/fugaも消してしまう。
registryだけが残っている状態だ。
ではlocalhost:5000/fugaをpullしてみる。

```
$ docker pull localhost:5000/fuga
```
うまく取れただろうか？
起動して中にさっき作ったテキストファイルがあるかを確認しよう。

```
$ docker run -it localhost:5000/fuga
```
ここで`cat /opt/f.txt`として`helohelo`とふざけたテキストが出ただろうか？

さっきイタズラしたコンテナが、ちゃんとレジストリに登録されていて取得できる事が確認できれば成功である。

# 付録：出やすいエラーとその対処
## docker psでForbidden
`exit`でdocker-machineから抜けてPowerShellに戻って欲しい。
今度はPowerShell上から直接dockerを触ってみよう。

ここまでの手順だとプロキシ環境の人は、

```
PS > docker ps
error during connect: Get https://192.168.99.100:2376/v1.39/containers/json: Forbidden
```
こんな事になってる人もいるんじゃないかと思う。
これはプロキシを潜ろうとしているためだ。

```
PS > $env:no_proxy = "192.168.99.100"
PS > docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
cf53abe18d8a        registry            "/entrypoint.sh /etc"   17 hours ago        Up 17 hours         0.0.0.0:5000->5000/tcp   romantic_bardeen
```

## docker-machine envでTLSなんちゃら
```
PS > docker-machine env
Error checking TLS connection: Error checking and/or regenerating the certs:
(略)
```
これはTLS証明書を再生成すればよい。

```
PS > docker-machine regenerate-certs default
```

## scoopからインストールしたらdocker.jsonはどこにおけばいいの？
```
~/scoop/apps/docker/current/config
```
この辺に置けばOKだ。configディレクトリは自分で作ろう。これでプライベートからの取得も怖くないぜ。


# おわりに
このくらい触るとなんとなく**Dockerって何が嬉しいの？**という疑問に対して、多少なりとも分かりかけてきたような気がしないでもない可能性があると言えなくもないかも知れない、程度にはなったのではないだろうか？ <font color="LightGray">という気がしないでもないと言えなくもないと思うって高畑充希が言ってたかも知れないという夢を見たという人が隣に住んでいるらしい。</font>

聞くより見るより触るのが早い。因みに**百見は一触に如かず**は俺の尊敬する格闘家の範馬勇次郎さんの言葉で、**百見は一験に如かず**は経営者の松下幸之助さんの言葉である。

余談の余談であるが、百聞は一見に如かずには続きがある。
百聞は一見に如かず、百見は一考に如かず、百考は一行に如かず、百行は一果に如かず、と続くのである。

ちょっとした豆知識を載せる事でそれっぽい記事のように見せかけたところで、オチを有耶無耶にして記事を終わる高度な作戦である。