しばたテックブログ

気分で書いている技術ブログです。

PowerShellでDockerを操作する方法についてあれやこれや

うまくまとめることが出来ず雑多な話になっています。

基本的にはWindows Server 2016およびWindows 10を対象としていますが、その他のOSも対象になる場合があります。

1. 変更されたDockerのインストール手順について

基本的にWindows Server 2016を対象とした話しです。
ただ今後Windows 10も対象になるかもしれません。

Windows Server 2016向けのDockerのインストール手順はMSDNの以下のページに記載されています。

msdn.microsoft.com

以前はInvoke-WebRequestコマンドレットを使ってdocker.exeおよびdockerd.exeをダウンロードしサービス登録を行うといった手順だったのですが、つい先日その手順が更新され、コンテナーの機能も含めてInstall-Packegeから行う様に変更されていました。

リンク先にありますが、手順はざっとこんな感じになります。

# Providerのインストール
Install-Module -Name DockerMsftProvider -Repository PSGallery -Force
# コンテナーの機能の追加+Dockerのインストール
Install-Package -Name docker -ProviderName DockerMsftProvider
# 再起動
Restart-Computer

最初にDockerMsftProviderという新しいProviderをインストールし、このProviderからパッケージとしてDockerをインストールします。

Install-Packegeをした時点で、コンテナーの機能を追加し、C:\Program Files\Dockerdocker.exedockerd.exeがインストールされ、dockerd.exedockerサービスとして登録されます。

コンテナーの機能を有効にするにはサーバーを再起動があるため、再起動後にDockerを使える様になります。

あと、DockerMsftProviderのIssueに

github.com

が挙げられており、現在Windows 10ではこの方法は使えません。
(Windows10ではInstall-WindowsFeatureは使えずEnable-WindowsOptionalFeatureを使う必要があるため)

このIssueがどう対応されるかまだわかりませんが、おそらくは将来的にWindows 10サポートもあるのかなと考えています。

なお、現時点ではこのProviderにあるパッケージはDockerのみです。
いずれ周辺ツールのインストールも可能になるかもしれませんが、まだなんとも言えない感じです。

# 現在 Find-Package しても Docker 以外のものは存在しない
PS C:\> Find-Package –ProviderName DockerMsftProvider

Name                           Version          Source           Summary
----                           -------          ------           -------
Docker                         1.12.2-cs2-ws... DockerDefault    Contains the CS Docker Engine for use with Windows ...

2. 利用可能なContainer Cmdletについて

これはWindows Server 2016およびWindows 10を対象とした話しです。

コンテナーの機能を追加するとWindows Serverコンテナー/Hyper-Vコンテナーを操作するためのContainer Cmdletsを利用することができます。

Get-Commandを使って公開されているコマンドレットを見ると以下の様になります。

PS C:\> Get-Command -Module Containers

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Cmdlet          Get-ContainerNetwork                               1.0.0.0    Containers
Cmdlet          New-ContainerNetwork                               1.0.0.0    Containers
Cmdlet          Remove-ContainerNetwork                            1.0.0.0    Containers

2016/10/20現在のMSDN(Containers Cmdlets)を見ると21個のコマンドレットが定義されているにも関わらず、実際にはコンテナー用仮想ネットワークに関するGet-ContainerNetworkNew-ContainerNetworkRemove-ContainerNetworkの3つだけしかありません。

これについては、PowerShell for Docker | Microsoft Docs に理由が記載されています。
いつドキュメントが更新されるかわからないので、要所だけ引用しておくと、

フォーラム、Twitter、GitHub を介したお客様との対話、さらには直接の対話を通して、"どうして PowerShell から Docker コンテナーを表示できないのか" という問いをよく耳にします。
 
長所、短所、およびさまざまなオプションについて、お客様と話し合った結果、コンテナー PowerShell モジュールの更新が必要であるという結論に達しました。 そのため、Windows Server 2016 のプレビュー ビルドに同梱されているコンテナー PowerShell モジュールを非推奨とし、Docker 用の新しい PowerShell モジュールへの置き換え作業を開始しました。

とある様に、当初(私の記憶ではWindows Server 2016 TP3~TP5くらいの間)はDockerに依存しないContainer Cmdlets(上記のMSDNに記載されているもの)を開発していたのですが、これを中止(中断?)しDocker専用のコマンドレットの開発にシフトしたため利用可能なコマンドレットが減っています。

今後Container Cmdletsのコマンドレットが増えるのかは不明です。

3. PowerShell Module for Docker

で、前項で触れたDocker専用のコマンドレットがこちらになります。

github.com

概要

こちらは雑に言ってしまうとdockerコマンドのPowerShell Cmdlet版です。
まだアルファ版のためすべての機能を網羅でききていませんし、バギーな部分もありますが、1コマンドレットが1dockerコマンドに対応する様です。

そして、このコマンドレットは内部でDocker.DotNetという.NETからDockerを操作するためのライブラリを使用しています。
Docker.DotNetはLinux用のDocker Engine、Windows用のDocker Engine両方に対応している*1ので、コマンドレットもどちらのDocker Engineに対して利用可能です。

余談ですが、Docker.DotNetは内部でDocker Remote APIを呼んでいるだけなのでdockerの実行バイナリが必要といった依存関係はありません。

対象OS

このコマンドレットを利用可能なOSは、

PowerShell 5 (available in Windows 10, Server 2016 Preview, or by installing WMF 5) or PowerShell 6 Preview (available for Windows, Linux, and Mac OS X)

との事で、PowerShell 5.0以降であればどの環境でも動く様です。
私は全機能ではありませんが、Windows 10とWindows Server 2016でコマンドレットが使えることを確認しています。

インストール手順

まだアルファ版のためAppVeyor上のリポジトリからモジュールを取得する必要があります。
手順は以下。

# AppVeyor上のリポジトリからインストール
Register-PSRepository -Name DockerPS-Dev -SourceLocation https://ci.appveyor.com/nuget/docker-powershell-dev
Install-Module Docker -Repository DockerPS-Dev -Scope CurrentUser
# 必要があればUpdate-Moduleする
# Update-Module Docker

まだなんとも言えませんが、もしかしたら将来、先述のDockerMsftProviderからインストール可能になるのかもしれませんね...

コマンドレットの一覧

全てのコマンドレットの説明をするのはつらい(というか無理)なので、コマンドレット・エイリアスの一覧と対応するdockerコマンドのリストを記載しておきます。

本エントリ時点でのバージョンはVer.0.1.0.100です。

PowerShell Cmdlet Alias (おおむね)対応するdockerコマンド
ConvertTo-ContainerImage Commit-Container docker commit
Copy-ContainerFile - docker cp
Enter-ContainerSession Attach-Container docker attach
Export-ContainerImage Save-ContainerImage docker save
Get-Container - docker ps -a
Get-ContainerDetail - docker inspect
Get-ContainerImage - docker images
Get-ContainerNet - docker network ls
Get-ContainerNetDetail - docker network inspect
Import-ContainerImage Load-ContainerImage docker load/docker import (tarballの入力のみ可)
Invoke-ContainerImage Run-ContainerImage docker run
New-Container - docker create
New-ContainerImage Build-ContainerImage docker build
New-ContainerNet - docker network create
Remove-Container - docker rm
Remove-ContainerImage - docker rmi
Remove-ContainerNet - docker netowrk rm
Request-ContainerImage Pull-ContainerImage docker pull
Set-ContainerImageTag Tag-ContainerImage docker tag
Start-Container - docker start
Start-ContainerProcess Exec-Container docker exec
Stop-Container - docker stop
Submit-ContainerImage Push-ContainerImage docker push
Wait-Container - docker wait

実際にこのコマンドレットを利用してみればわかりますが、対応するdockerコマンドについては100%の互換を持つわけではなく、微妙な違いがありますので注意してください。
コマンドレットで用を成せない場合はdockerコマンドを使うしかありません。

dockerコマンドとの使い分けについて

率直に言ってしまうと現時点ではPowerShell Module for Dockerはdockerコマンドの劣化版ですし、将来的にもdockerコマンドと完璧に対になるかといえばそうはならないと思います。
なのでPowerShell Module for Dockerとdockerコマンドは用途に応じて使い分けてやる必要があると思います。

あくまで私個人の想いですが、コンソール上で手早くDockerを操作する場合はdockerコマンドを、スクリプトによる自動化を行う場合はPowerShell Module for Dockerを使ってやるのが良いと思います。

例えば以下の様な処理をスクリプト化して定期的に実行してやれば消し忘れたコンテナを綺麗に消してやることができます。

# 停止してから24時間以上経ったコンテナを削除する処理
Get-Container `
    | Where-Object {
        if ( $_.State -ne "exited") {
            return $false
        }
        $detail = Get-ContainerDetail -Container $_
        if ( [Datetime]::Now.Subtract([Datetime]::Parse($detail.State.FinishedAt)).Hours -lt 24 ) {
            return $false
        } 
        return $true
     } `
    | Remove-Container

こういった処理をdockerコマンドで頑張るにはつらみがあると思いますし、PowerShellでやればかなり楽ができると思います。

あと完全に個人的な話ですが、私はDockerを検証用に使ってるのためコンソール上の操作でも、

# コンテナをまるっと全削除
Get-Container | Remove-Container -Force

といった感じでコンテナをまるっと消したりするのにコマンドレットを使っています。
何気にこの処理をdockerコマンドでやろうとするとめんどうくさいんですよね...

最後に

とりあえずこんな感じです。
PowerShellからDockerを扱う方法についてとりとめもなく書いていきました。

PowerShell Module for DockerについてはWindowsに限らず使えますので、非Windowsな環境でもDocker管理の自動化をしたい場合に使いどころがあるかと思います。
まだアルファ版ですが発展していくツールだとは思いますのでダメ元で使ってみるのも良いかもしれません。

*1:このライブラリのVer.1.0.0は2014年リリース