Windows- und Linux-basierte Docker-Container auf Windows nutzen (Teil 2 von 2)

Nachdem die Grundlagen zu Windows-Containern im ersten Teil vermittelt wurden, geht es nun um Details zur Verwendung, um Linux-Container unter Windows und die Verbreitung von Containern im Allgemeinen.

In Pocket speichern vorlesen Druckansicht
Windows- und Linux-basierte Docker-Container auf Windows nutzen, Teil 2 von 2
Lesezeit: 19 Min.
Von
  • Dr. Holger Schwichtenberg
Inhaltsverzeichnis

Per Get-ContainerImage sieht man nach den in Teil 1 des Artikels beschriebenen Schritten das Basis-Image microsoft/aspnet:latest und das Image für die Webanwendung: wwwings.web:dev im Debug-Modus und wwwings.web:latest im Release-Modus. Beide Images lassen sich natürlich auch von der Kommandozeile außerhalb von Visual Studio starten, beispielsweise

Run-ContainerImage -ID wwwings.web:latest -Name Webserver -Detach

beziehungsweise

docker run --name Webserver --detach  wwwings.web:latest  

Die IP-Adresse eines Containers lässt sich auch erfragen, indem man ipconfig im Container ausführt. Die Übergabe eines Parameters wie /all für den im Container auszuführenden Befehl ist in der aktuellen Version der PowerShell-Commandlets für Docker sehr umständlich:

Start-ContainerProcess -ID Webserver -Command @("ipconfig", "/all") 
Mit docker.exe geht es einfacher: docker exec Webserver ipconfig /all

Alternativ dazu lässt sich auch eine Konsolenverbindung mit dem Docker-Container eröffnen. Mit den PowerShell-Commandlets funktioniert das sowohl über das spezielle Commandlet Start-ContainerProcess als auch das allgemeine Enter-PSSession, wobei letzteres nur eine Container-ID erwartet und keinen Container-Namen erlaubt – daher die Übersetzung von Namen in ID mit dem Ausdruck (Get-Container Webserver).ID:

Start-ContainerProcess -ID Webserver -Command powershell.exe -Terminal
Enter-PSSession -ContainerId (Get-Container Webserver).ID
Alternativ über docker.exe: docker exec -it Webserver powershell.exe

Der Parameter -Terminal beziehungsweise -it ist notwendig, damit man mit der im Gast gestarteten PowerShell interagieren kann. Während Enter-PSSession auch in der PowerShell ISE funktioniert, lassen sich die anderen beiden Befehle dort aktuell nicht nutzen.

Auch bei Run-ContainerImage beziehungsweise docker run kann man bereits einen Befehl angeben, der direkt beim Start des Containers auszuführen ist:

Run-ContainerImage -ID wwwings.web:latest -Terminal -Name Webserver ↵ 
-Command powershell.exe

beziehungsweise

docker run --name Webserver -it wwwings.web:latest powershell.exe 

Das Nachstellen eines im Container auszuführenden Befehls hilft aber nichts bei Images, die selbst einen expliziten Entry Point definiert haben, denn hier hängt Docker den nachgestellten Befehl nur als Parameter an die Entry-Point-Anweisung an. So ist es für das oben verwendete wwwings.web:latest notwendig, den Entry Point bei docker run umzudefinieren:

docker run -it --entrypoint=powershell wwwings.web:latest

Mit der PowerShell geht das nur über das explizite Befüllen eines Config-Objekts:

$config = [Docker.DotNet.Models.Config]::new()
$ep = [System.Collections.Generic.list[string]]::new()
$ep.Add("powershell.exe")
$config.Entrypoint = $ep
Run-ContainerImage -ID wwwings.web:latest -Configuration $config ↵
-Terminal -Name Webserver

Der Befehl docker run ermöglicht auch Ressourcenbeschränkungen, zum Beispiel bedeutet docker run -it -m 500M --cpu-quota 50000 wwwings.web:latest, dass der Arbeitsspeicher auf 500 MB und die CPU-Nutzung auf 50 Prozent (die Angabe 100000 entspricht dabei 100 %) beschränkt ist. Mit der PowerShell muss man wieder etwas umständlicher vorher ein HostConfig-Objekt erzeugen. Immerhin ist dort die CPU-Angabe einfacher in Prozent zu erledigen:

$hostConfig = [Docker.DotNet.Models.HostConfig]::new()
$hostconfig.CPUPercent = 50
$hostconfig.Memory = 500MB
Run-ContainerImage -id wwwings.web:latest -Detach -HostConfiguration↵
$hostConfig -Name Webserver

Häufig ist es auch notwendig, Dateien zwischen Host und Container auszutauschen. Das erledigt man mit Copy-ContainerFile beziehungsweise docker cp:

Copy-ContainerFile -Path c:\web\index.htm -Destination c:\inetpub\wwwroot\ ↵ 
-ID Webserver -ToContainer

oder:

docker cp c:\web\index.htm Webserver:c:\inetpub\wwwroot\

Das Kopieren von Dateien und den Start von Anwendungen können Entwickler auch direkt in ein dockerfile einbauen. Der folgende Quelltextauszug kopiert ein PowerShell-Skript in das Image und führt das Skript aus, das in dem Image eine Datei index.html anlegt:

# Autor
MAINTAINER Holger Schwichtenberg "hs@IT-Visions.de"
# Basisimage festlegen (IIS auf Windows Server 2016 Core)
FROM microsoft/iis
# Bisherigen Inhalt löschen
RUN del C:\inetpub\wwwroot\*.* /F /Q
# Grafikdatein kopieren
COPY Logo.jpg C:/inetpub/wwwroot/Logo.jpg
# PowerShell-Skript kopieren und ausführen
RUN MD c:\temp
COPY create_index_html.ps1 C:/temp/script.ps1
RUN powershell.exe -executionpolicy bypass c:\temp\script.ps1
# Aufräumen
RUN del C:/temp/script.ps1

Der Editor Visual Studio unterstützt bei der Eingabe von Befehlen in dockerfile, gibt aber anders als der kleine Bruder Visual Studio Code mit der Erweiterung vscode-docker keine Vorschläge für Image-Namen nach FROM.

Wenn der Container nicht per Network Address Translation angesprochen werden, sondern eine IP-Adresse im Subnetz des Hosts erhalten soll, ist dafür zunächst ein Docker-Netzwerk anzulegen. Das ist aktuell nicht über PowerShell-Commandlets, sondern nur über Docker.exe möglich:

docker network create -d transparent Brücke 

Dieses neue Netzwerk mit dem Namen "Brücke" sollte nun in der Liste der Docker-Netzwerke erscheinen, die man mit Get-Containernet (oder: docker network ls) ausgibt. Danach kann man beim Start des Containers auf das Docker-Netzwerk Bezug nehmen:

$hostConfig = [Docker.DotNet.Models.HostConfig]::new()
$hostConfig.NetworkMode = "Brücke"
Run-ContainerImage -ID wwwings.web:latest -Detach -HostConfiguration ↵
$hostConfig -Name Webserver

Deutlich prägnanter ist dies in der klassischen Variante:

docker run -detach --network Brücke --name Webserver wwwings.web:latest  

Die Parameter mit Namen "detach" bedeuten dabei jeweils, dass der Container ohne Ausgaben an der Standardausgabe im Hintergrund laufen soll. Es ist auch möglich, einen Container anzulegen, ohne ihn direkt zu starten (hier wieder unter Bezug auf das zuvor definierte HostConfig-Objekt):

New-Container wwwings.web:latest -HostConfiguration $hostConfig -Name Webserver 

beziehungsweise

docker container create --name Webserver --network Brücke wwwings.web:latest 

Der Container ist nun erstellt, läuft aber noch nicht. Später kann man ihn mit Start-Container -ID Webserver oder [/i]docker start Webserver[/i] starten. Zum Anhalten eines laufenden Containers lässt sich Stop-Container -ID Webserver beziehungsweise docker stop Webserver verwenden.

Mit der PowerShell ist es elegant, alle laufenden Container eines Images zu beenden beziehungsweise zu löschen:

Get-container | Where-Object { $_.Image -eq "wwwings.web:latest" -and $_.status↵ 
-Like "Up*" } | Stop-Container
Get-container | Where-Object { $_.Image -eq "wwwings.web:latest" } | Remove- ↵
Container

Images wird man schnell los, wobei sich nur die löschen lassen, für die es keinen Container mehr gibt und die auch nicht Basis für andere Images sind:

Get-ContainerImage | Remove-ContainerImage 

Daher ist es in Visual Studio auch nicht möglich, ein Image neu erzeugen, wenn es noch Container für die bisherige Version gibt ("unable to delete - image is being used by running container").