Windows 用 Docker image を macOS で動かす

f:id:lambdalisue:20181029145429g:plain

どうも有末です。 「仕事で使ってない技術でもいいからブログ書いてくれると嬉しい」と言われ、嬉しさのあまり涙で画面が曇ったので、情報を探すのに苦労した Windows 用 Docker image を macOS で走らせる方法に関して書きます。

僕は弊社プログラマの中で最も多くの Vim プラグインを開発1しています(たぶん)。 基本的にプラグインを開発する際は対象の OS を絞らないように作っているのですが、どうしても普段利用していない Windows や Linux では環境依存のバグが発生することが有ります。 そのため TravisCI (Linux/macOS) や AppVeyor (Windows) を用いて他の OS でも CI テストを回すようにしているのですが、テストが落ちたときに原因特定するのはとても面倒です。

このような場合、テスト環境を Docker にて準備するとローカルでも同じ環境でテストが出来るため色々と捗るのですが Windows 用 Docker image は Windows container でしか動作しません(当たり前ですが)。 ただ、今回みたいなケースはサクッとテスト用に走らせたいだけなので Virtual Box とか駆使したら何とかならないかな?と色々探したところ StefanScherer/windows-docker-machine というお手軽なシステムを見つけたのでご紹介します。 ちなみにパフォーマンスとかライセンスとか諸々あるので運用利用する場合は素直に Windows ホストでやったほうが無難です。

やりたいこと

macOS のターミナルから Windows container を要求する Docker image (例: microsoft/dotnet-samples:dotnetapp-nanoserver)を可能な限りサクッと動かす。

ちなみに Docker for Mac の状態では上記 Docker image の実行は image operating system "windows" cannot be used on this platform. とか言われて動きません。

$ docker run --rm microsoft/dotnet-samples:dotnetapp-nanoserver
Unable to find image 'microsoft/dotnet-samples:dotnetapp-nanoserver' locally
dotnetapp-nanoserver: Pulling from microsoft/dotnet-samples
bce2fbc256ea: Pulling fs layer
b0b5e40cb939: Pulling fs layer
347417e0cada: Pulling fs layer
1e5ea1830940: Pulling fs layer
081f63111c09: Pulling fs layer
94504ab92c8e: Pulling fs layer
4b830cd70a22: Pulling fs layer
c09304867c0b: Pulling fs layer
04d6c936784e: Pulling fs layer
5897a999aef6: Pulling fs layer
b33a195869b0: Pulling fs layer
081f63111c09: Waiting
94504ab92c8e: Waiting
4b830cd70a22: Waiting
04d6c936784e: Waiting
b33a195869b0: Waiting
5897a999aef6: Waiting
1e5ea1830940: Waiting
c09304867c0b: Waiting
docker: image operating system "windows" cannot be used on this platform.
See 'docker run --help'.

依存アプリのインストール

Vagrant および Virtual Box を利用するので Homebrew Cask を利用してインストールしておく。

$ brew cask install vagrant virtualbox

Docker machine の構築

Docker がインストールされた Windows Server 2016 をベースに Windows container を動かすための Docker machine を構築します。 作業内容としては StefanScherer/windows-docker-machine をクローンしてきて vagrant up 2016-box 2 するだけです。 なお、初回構築時はダウンロード等で結構時間がかかります。

$ git clone https://github.com/StefanScherer/windows-docker-machine
$ cd windows-docker-machine
$ vagrant up 2016-box  # 初回は珈琲飲むくらいの時間はかかる

Docker machine の確認

上記で構築が完了すると以下のように docker-machine ls2016-box が出てきます。

$ docker-machine ls
NAME       ACTIVE   DRIVER    STATE     URL                        SWARM   DOCKER          ERRORS
2016-box   -        generic   Running   tcp://192.168.99.90:2376           v18.03.1-ee-3   

このように Windows container を動かすための環境が Docker machine 化したので、以下のように簡単に利用できます。

$ eval $(docker-machine env 2016-box)

なお、上記コマンド実行後に docker version を見ると ServerOS/Archwindows/amd64 になっています。

$ docker version
Client:
 Version:           18.06.1-ce
 API version:       1.37 (downgraded from 1.38)
 Go version:        go1.10.3
 Git commit:        e68fc7a
 Built:             Tue Aug 21 17:21:31 2018
 OS/Arch:           darwin/amd64
 Experimental:      false

Server:
 Engine:
  Version:          18.03.1-ee-3
  API version:      1.37 (minimum version 1.15)
  Go version:       go1.10.2
  Git commit:       b9a5c95
  Built:            Thu Aug 30 18:56:49 2018
  OS/Arch:          windows/amd64
  Experimental:     false

動かしてみる

この状態であれば Windows container が必要な microsoft/dotnet-samples:dotnetapp-nanoserver がちゃんと動作して、よくわからないキャラクターっぽいものが表示されます。

$ docker run --rm microsoft/dotnet-samples:dotnetapp-nanoserver

        Dotnet-bot: Welcome to using .NET Core!
    __________________
                      \
                       \
                          ....
                          ....'
                           ....
                        ..........
                    .............'..'..
                 ................'..'.....
               .......'..........'..'..'....
              ........'..........'..'..'.....
             .'....'..'..........'..'.......'.
             .'..................'...   ......
             .  ......'.........         .....
             .                           ......
            ..    .            ..        ......
           ....       .                 .......
           ......  .......          ............
            ................  ......................
            ........................'................
           ......................'..'......    .......
        .........................'..'.....       .......
     ........    ..'.............'..'....      ..........
   ..'..'...      ...............'.......      ..........
  ...'......     ...... ..........  ......         .......
 ...........   .......              ........        ......
.......        '...'.'.              '.'.'.'         ....
.......       .....'..               ..'.....
   ..       ..........               ..'........
          ............               ..............
         .............               '..............
        ...........'..              .'.'............
       ...............              .'.'.............
      .............'..               ..'..'...........
      ...............                 .'..............
       .........                        ..............
        .....


**Environment**
Platform: .NET Core 2.0
OS: Microsoft Windows 10.0.14393 

なお Docker machine なので docker-machine env --unset を eval すれば戻ります。

$ eval $(docker-machine env --unset)

$ docker version
Client:
 Version:           18.06.1-ce
 API version:       1.38
 Go version:        go1.10.3
 Git commit:        e68fc7a
 Built:             Tue Aug 21 17:21:31 2018
 OS/Arch:           darwin/amd64
 Experimental:      false

Server:
 Engine:
  Version:          18.06.1-ce
  API version:      1.38 (minimum version 1.12)
  Go version:       go1.10.3
  Git commit:       e68fc7a
  Built:            Tue Aug 21 17:29:02 2018
  OS/Arch:          linux/amd64
  Experimental:     true

おわりに

macOS からサクッと Windows container を動かすことが出来るようになったため Dockerfile 書くための試行錯誤とかも比較的楽にできるようになりました。 ここまで出来てひとまず満足してしまったので、まだ CI に活かすとかは出来てませんが…… とりあえず、Docker 便利。


  1. 残念ながら弊社の仕事として Vim プラグインを開発しているわけではありません。あくまでも趣味です。

  2. 簡略化のために 2016-box を指定していますが、通常は README の通り StefanScherer/packer-windows を使って自前構築する方が良いと思います(びっくりするくらい時間かかりますが)。

一般ユーザアカウントで取得できる構成情報を追加しました 他

Kompira cloudについて、以下の内容を含むアップデートを行いました。

一般ユーザアカウントで取得できる構成情報を追加しました

SSH経由でスキャンする際、一般ユーザアカウントでも以下の構成情報が取得できるようにしました。

  • 製品モデル名
  • 製品バージョン番号
  • 製品ベンダ名
  • メモリ容量
  • ストレージドライブ数
  • ストレージ容量

スペース名称を変更できるようになりました

スペースお申込み時に指定頂いたスペースの表示名称を変更できるようになりました。
画面右上の「全体設定」>「スペース」より変更することができます。
また、この画面で現在契約しているプラン名称を確認することもできます。

構成情報は、魔法のExcelで管理?

Kompira cloudチームのUI/UX担当、福原です。
WEBサービスのUXと言うと、画面を操作したときの体験だと思っている方も多いでしょう。
でもそれはUXのほんの一部にすぎません。UXとは製品の情報に接したときから使用中、使用後全てを含む包括的な概念になります。 様々な立場で語られることの多いUXですが、実はISOでその概念がちゃんと定義されているのです。

ISO9241-210によれば、UXとは
「製品、システム又はサービスの使用及び/又は使用を想定したことにより生じる個人の知覚と反応」
とされています。

なんだか小難しい言い回しで結局なに?と思いますよね。

つまり、Kompira cloudのUXという観点で考えると、これを使用するユーザが手作業の運用に疲れ果てていて、これをなんとかしたい。検索してみたらKompira cloudの情報を見つけた。 なるほどこんなことができるのかと期待をし、上司を説得して製品を導入し、期待する効果を得ることができ、満足して使用を継続する。(ポジティブに考えすぎですが) この一連の流れ全てがUXだということになります。

ということで、UXデザイナーとして営業に同行し、現場の皆様のお話を聞く機会も多いのですが、
とにかく皆さん本当に大変ですね。

f:id:fukuharax:20181025165316p:plain

IT業界といえど、実は泥臭い手作業が山のように積まれている上に、ミスは許されないという状態。 なかでも、構成情報に関しては管理を自動化されているとおっしゃる企業様には今のところ一社もお目にかかれていません。
「構成管理はどのようにされていますか?」
この質問は数十社にさせて頂きました。
そうすると、必ずと言っていいほど少し苦笑いして、

「実は手作業なんですよね。常に最新かって?いえいえ、そんなことはムリです」

このようにおっしゃいます。

自社に置き換えて考えても、手作業の管理で常に最新状態に保つというのは100%無理と言っても過言ではないと思います。

f:id:fukuharax:20181025165820p:plain

「構成情報?魔法のExcelで管理してますよ」
とユーモアたっぷりにお答えいただいた企業様もいらっしゃいました。

Excelって確かに便利なんです。 とりあえず何か管理するならこんな便利なツールはありません。
ただ、そのデータを確認する人が数人~数十人になったり、各々が更新したりということになると話は別ですし、
何と言っても構成が変わるたびに更新する労力は大変なものです。
実際にお会いしてお話を聞くと、早く皆さんを楽にしてあげたいなあ~と切に思います。
もちろん、現場の課題は構成管理だけではなく、多岐に渡るのでしょう。

運用の担当者の課題を解決するためには、何が必要なんだろう?

UI/UX担当として、日々そんな探求心を元に皆様のお話をお聞きしています。

Azure Container Instancesを利用し、Azure上でよくある構成をセキュアにする

クラウドチームの関戸です。 Azure Container Instancesが9/25にGAしました 。 GAの告知を見ている中で、Virtual Networkへの統合機能がPreviewされていることを知ったため、本記事ではAzure Container InstancesがVirtual Networkに統合されたことにより、Azure上のインフラセットをこれまでよりセキュアする案を思いついたため、その案の検証をしてみます。

さて、Azure上に下図のように、

よくある構成
よくある構成

  • Appサーバ
  • 踏み台サーバ

という構成を組むことは比較的多いのではないでしょうか。 Appサーバは80ポートを通してのみアクセスが可能で、解放されているポートもNetworkSecurityGroupで絞られています。 現実的には、ここにLoadBalancerなどを追加して負荷分散したりしますが、以下では話を単純にするためAppサーバと踏み台サーバに登場人物を絞ります。

このとき、踏み台として利用するサーバに対して、

  • 使うタイミングは少ないのに用意しておかなければならない
  • 使う度に踏み台を起動/終了すると待たされるのが嫌
  • 起動し続けるとして、セキュアな環境構築やID管理が手間
  • 踏み台に対する利用料金が意外とかかる

と様々な不満がありました。

踏み台用のVMを普段は落としておき、使うときだけ起動する、という運用であれば、Appサーバに対する不正なログインの懸念はかなり下がります。 ただし、さきほど挙げたように、このような運用には踏み台用VMの起動のオーバヘッドであったり、不満があった訳です。 結果的に、踏み台用VMは常時起動し続けることになったりし、せっかくのセキュアな構成なのに... と更に不満が出たりしていました。 Azure Container InstancesがVirtual Networkに統合されることによって、上記のような従来型の構成に対する不満をかなり解消できる方法がうまいことAzure上で構成可能になりました。

まず、Azure Container Instancesの(本記事における)利点は起動が高速なこと、に尽きます。 コマンド発行から数秒程度で起動します。

※現状、Virtual Networkに初回デプロイするときは、そこそこ時間がかかってしまってます(10分弱)
※デプロイ済であれば、通常通り数秒程度で起動します

Azure Container Instancesで起動するコンテナを踏み台として利用することで、Virtual Machineの起動/終了に伴う待ち時間をほぼ無くすことができます。 また、Virtual Machineのカスタマイズ(起動後にやったり、カスタムVM Imageを用意したり)は結構手間で動作確認も大変でしたが、Dockerfileの整備をすれば良くなります。 コンテナのため、ローカルでの動作確認も手軽にできます。

さて、Azure Container Instancesを踏み台として利用する場合、下図のような構成になります。

Azure Container Instancesを踏み台利用する構成
Azure Container Instancesを踏み台利用する構成

大きな違いは、踏み台関連のリソースが削除されていることと、Azure Container Instancesが追加されていることです。 他のリソースに差はないため、本筋のサービスに影響を与えずに適用可能です。

図中で、システム管理者はコンテナに対してコンテナにTTYをアタッチすると記載していますが、 こちらのドキュメントにある通り 、現状ではVirtual Networkに接続するコンテナは、同時にPublic IPを持てないためです。

Container groups deployed to a virtual network do not currently support public IP addresses or DNS name labels.

currently と書かれているため、今後に期待ですね。 そのため現状では、sshdを実行し接続することはできませんから、 docker exec 相当の az container exec を使って、リモートシェルを開くことにします。

ではこの構成での、踏み台からAppサーバへのssh接続を、 Azure CLI v2 を利用してやってみます。 サンプルリポジトリ にお試し用のスクリプトをまとめてありますので、試してみたい方はどうぞ。 なお、Azure CLI v2のバージョンは2.0.49です。

#!/bin/bash

git clone https://github.com/fixpoint/azure-container-instances-as-a-bastion
cd azure-container-instances-as-a-bastion

# お試し用のリソースを作成
# Azure Container Instancesはまだいくつかのリージョンでしか利用できないため、westusに作成する
az group create --name aci --location westus
az group deployment create --resource-group aci --template-file ./azure.template.json

# deploymentのoutputsから、Virtual Networkのリソース名を取る
vnet_name="$(az group deployment show --resource-group aci --name azure.template --output tsv --query properties.outputs.vnetName.value)"

# 踏み台用コンテナグループを作成します
# 今回は公式イメージのalpineを利用します、利用中には常駐させるため --command-line でsleepをループさせています
az container create \
    --resource-group aci \
    --name bastion \
    --image library/alpine:3.7 \
    --cpu 1 \
    --memory 0.5 \
    --vnet-name "${vnet_name}" \
    --vnet-address-prefix "10.0.0.0/16" \
    --subnet bastion-subnet \
    --subnet-address-prefix "10.0.1.0/24" \
    --command-line "/bin/sh -c 'while true; do sleep 1s; done'" \
    --restart-policy Never

# 起動したコンテナでシェルを起動します
# 現状、Windowsではaz container execコマンドはうまく動きませんので、LinuxかMacを使ってください
az container exec \
    --resource-group aci \
    --name bastion \
    --exec-command "/bin/sh"

# ここから、踏み台上での操作
# sshにalpineの環境を整えます
apk add --no-cache openssh-client
mkdir ~/.ssh
# サンプルリポジトリのprivate.pemの内容をコピーして持っていってください
vi ~/.ssh/id_rsa
chmod 0400 ~/.ssh/id_rsa

# Appサーバにsshします
# AppサーバのPrivate IPを、Azureポータルから確認しておいてください
# ここでは、10.0.0.4と仮定しています
ssh azure-user@10.0.0.4

# これでAppサーバに接続できました

# ここまで、踏み台上での操作

# 使い終わったため、コンテナを終了させる
az container stop \
    --resource-group aci \
    --name bastion

# お試し用のリソースを削除
# 現在はAzure Container InstancesをVNETに繋げた場合、削除するために一手間必要になります
# https://docs.microsoft.com/ja-jp/azure/container-instances/container-instances-vnet#clean-up-resources
network_profile_id=$(az network profile list --resource-group aci --query [0].id --output tsv)
az network profile delete --id "${network_profile_id}" -y
sal_id=$(az network vnet subnet show --resource-group aci --vnet-name "${vnet_name}" --name bastion-subnet --query id --output tsv)/providers/Microsoft.ContainerInstance/serviceAssociationLinks/default
az resource delete --ids "${sal_id}" --api-version 2018-07-01
az network vnet subnet update --resource-group aci --vnet-name "${vnet_name}" --name bastion-subnet --remove delegations 0
az group delete --name aci --yes

※手元のazがバージョン古い場合は、 docker run --rm -it -v $HOME/.azure:/root/.azure microsoft/azure-cli:latest を利用すると便利です
※Docker Public Imageを起動する場合、例えば docker run nginx:alpine としていた場合は、 az container create --image library/nginx:alpine と、 library/ を付与する必要がありました

他にも色々と利用例は考えられますが、とにかく、Azure Container InstancesからVirtual Networkに接続できるだけで、とても夢が広がるというお話は理解していただけたかと思います。 今後、Virtual NetworkにデプロイしたコンテナにPublic IPを同時に持たせることができれば、よりカジュアルにセキュアにできるのではないでしょうか。

Azure Container Instancesの日本でのGAは、2018年の終わり頃になる予定です。 待ち通しいですね。

攻めの運用、責められない運用

フィックスポイント三角です。

気が付いたら2018年もあと2か月で終わろうとしています。 世の中変化も激しいし、あっという間に過ぎていってしまいますね。

ここ2,3年で採用環境も激変しているようで、 募集しても応募自体がない、応募があっても求める要綱に合致しないので採用に至らないという声をいたるところで聞きます。

経済産業省の調査によると、IT人材は現在でも17.1万人不足しており、2020年には36.9万人不足するそうです。 どうりで、採用が難しいはずですね。

そして、そんな大変な思いをして採用をしても、運用の現場に配属されると、すぐに辞めてしまう人が多いようです! 御社はいかがですか?

運用現場では、常に人が足りてない状態が慢性化しているところが沢山あります。

一方で、ユーザーからは、うちの運用は受け身で困る。もっと積極的に提案して欲しいのに、なんて言う事も聞かれます。

人がいないのにそんなことできるかー! という運用現場のマネージャーさんの声が聞こえてきそうですね。

なんで折角採用した人が辞めちゃうんでしょうか?

・配属されたときにはやる気をもっていても、やるべき事が決まっておりそれ以外の事は全くできない。

・過去の経緯の積み重ねを知らないと対応できず、自分の技術力を発揮できる場がない。

・何らかの活動をして上手くいっても当たり前、失敗するととても怒られる環境。

など、やる気をそぐ要因が次から次へと襲ってくるのが運用の現場です。

そのような環境に慣れてくると、次第に、依頼されないと動かない、依頼されても動きたくないようになってきて ユーザーからは頼りにならないと思われ、やる気のある人は別の職場に行ってしまうという状況になってるのではないでしょうか?

こう言う運用現場の守りのカルチャーを、プロフェッショナルとして、ユーザーにこちらから働き掛け、 システムの品質を高め、効率化を進めていく攻めの運用ができるように変えたい。

やる気のあるエンジニアが働きがいがあり、ユーザーも頼りになる運用チームにしたい。

そこに役に立つサービスを作りたい、そのような思いでKompira cloudをリリースしました。

こんな話をある人にしたところ、運用現場の人は、攻めの運用をしたいと言うより、 責められない運用をしたいと言う気持ちが強いんでは無いの?と言われましたが、、

あなたは攻めの運用か責められない運用かどちらの運用が良いですか?

RPMパッケージのリリースバージョンを取得できるようになりました 他

Kompira cloudについて、以下の内容を含むアップデートを行いました。

RPM系アプリケーション情報を取得する際、リリースバージョンを取得できるようになりました

これまでRPM系パッケージ情報は openssl 1.0.2k のように、バージョンまでを取得していましたが、今回のアップデートによりリリースバージョンまで取得するように変更しました。

取得するパッケージバージョン情報例
変更前 openssl 1.0.2k
変更後 openssl 1.0.2k-12.el7

この変更は、本日以降スキャンしたスナップショットに適用されます。

容量の表示形式を改善しました

メモリ容量やストレージ容量の表示を、これまではKB, MB, GB単位で表示していましたが、KiB, MiB, GiB単位で表示されるようにしました。

メモリ容量表示例
変更前 16.38 GB(17179869 kB)
変更後 16.00 GB(16777216 kB)

この変更は、本日以降スキャンしたスナップショットに適用されます。

その他バグ修正

  • Linux, Windowsからの構成情報取得時、タイムアウトにより情報取得に失敗する問題を改善しました。
  • 削除したネットワークに残っていたノードが、スペース全体で使用しているノードの個数としてカウントされてしまう問題を修正しました。
  • プロフィール情報の変更が即座に反映されない問題を修正しました。

また、あわせて ksocket についても、以下の内容を含むアップデートを行いました。

  • ksocketバージョン
    • ksocket: 1.4.3
    • ksoperations-networks: 1.5.2
  • 一部のAzure VNET上でスキャンが失敗する問題を修正しました。

最新の ksocket はこちらよりダウンロードすることができます。