Obraz kontenera to pakiet binarny zawierający wszystkie pliki oraz metadane niezbędne do uruchomienia kontenera
Obrazy kontenera możemy budować lokalnie lub pobrać z rejestrów (publicznych lub prywatnych)
Najpopularniejszym formatem obrazów jest ten wykorzystywany przez Dockera
Obraz Dockerowy jako plik to archiwum tar
, w którym umieszczone są metadane oraz warstwy
Każda warstwa składa się z własnych metadanych oraz kolejnego archiwum tar
zawierającego zestaw zmian jakie warstwa wprowadza
Główne metadane obrazu znajdują się w pliku manifest.json
np.:
[
{
"Config": "f63181f19b2fe819156dcb068b3b5bc036820bec7014c5f77277cfa341d4cb5e.json",
"RepoTags": ["ubuntu:latest"],
"Layers": ["151ae8ef4f042fd5173fd2497f0a365b4413468163e7bd567146f29dcfea3517/layer.tar", "2872658e1abe34d0c7391abbc0848fdeddb456659e39511df0574fcfc8b7ad70/layer.tar", "2b83a9243dd8405d0811beeb14aeb797745b100e4538d056adb63fcc6b47c59f/layer.tar"]
}
]
Mamy tutaj informację o użytych tagach dla tego obrazu w repozytorium (RepoTags
), listę warstw (Layers
) oraz ścieżkę do pliku konfiguracyjnego (Config
) zawierającego szereg informacji o wymaganej architekturze CPU, zmiennych środowiskowych, itp.
Alternatywnym standardem obrazów kontenerów jest format OCI (Open Container Initiative)
Jest to również archiwum tar
zawierające metadane oraz zestaw binarnych paczek (blobów)
Metadane znajdują się w pliku index.json
np.
{
"schemaVersion": 2,
"manifests": [
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:7ad481b55901a1b5472c0e1b3fbf0bf2867dc38feb6eb7a18cd310f00208e05c",
"size": 658
}
]
}
Manifest w formacie JSON znajduje się pliku blobs/7ad4...e05c
:
{
"schemaVersion": 2,
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"digest": "sha256:10bdc2317d43a5421151e135881e172002c7d61e934de7e1e79df560a151f112",
"size": 2427
},
"layers": [
{
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
"digest": "sha256:f3f8f4bd7c131f4d967bc162207ab72c24f427915682f895eb4f793ad05d7e35",
"size": 29989546
},
{
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
"digest": "sha256:0188b501936213b7cd0b5333245960781a8b035249cfa427fe9a229fe557c624",
"size": 924
},
{
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
"digest": "sha256:db861e57845ea7ba52a2ac277abbdd8cd04bda5db69c49bf95be49d11e5a47e1",
"size": 202
}
]
}
Podobnie jak w przykładzie dla Dockera, tutaj również mamy jeden plik konfiguracyjny oraz trzy pliki warstw
Oba przedstawione formaty dotyczą zapisu obrazu jako pojedynczego pliku, jednak taki projekt służy przede wszystkim wydajnemu cache’owaniu w przypadku transferu sieciowego
Kiedy pobierany jest obraz z rejestru to nie następuje ściągnięcie całego obrazu, ale porównanie które warstwy znajdują się już lokalnie i ściągnięcie tylko tych brakujących
Przykładowo:
cron
, ssh
)Dockerfile
zawierający instrukcję budowania (dokumentacja)FROM <image>
, gdzie image
to nazwa obrazu, na którym bazujemyRUN <command>
pozwala uruchomić komendę command
w ramach powstającego obrazu (np. instalacja pakietu, stworzenie pliku, itp.)CMD <command>
określa jaka jest domyślna komenda uruchamiana podczas startu konteneraEXPOSE <port>
dodaje metadane o tym, że aplikacje wewnątrz kontenera nasłuchuje na porcie port
EXPOSE
jest tylko formą dokumentacjiENV <key>=<value>
ustawia zmienne środowiskoweCOPY <src> <dest>
pozwala skopiować pliki do obrazu konteneraUSER <user>
ustawia bieżącego użytkownika (dalsze instrukcje poniżej USER
będą wykonywane na prawach user
)WORKDIR <path>
ustawia bieżący katalog roboczy (ścieżki relatywne w instrukcjach poniżej WORKDIR
będą rozwiązywane wg path
)ARG <name>
określa, że name
to argument, który należy podać na etapie budowania obrazuDockerfile
tworzymy przy pomocy komendy docker build -t mytag .
, gdzie mytag
oznacza nazwę obrazuDockerfile
<!-- index.html -->
<h1>Hello World from Docker!</h1>
FROM ubuntu
ENV DEBIAN_FRONTEND=noninteractive
COPY index.html /var/www/html/index.html
RUN apt-get update -y
RUN apt-get install -y apache2
EXPOSE 80
CMD ["/usr/sbin/apachectl", "-DFOREGROUND"]
/bigfile
, a obraz B rozszerza A poprzez usunięcie /bigfile
, to i tak obraz kontenera B będzie zawierał wewnętrznie warstwę z zawartością pliku, której i tak użytkownik końcowy nie będzie mógł odczytaćDockerfile
każda instrukcja tworzy osobną warstwę:
RUN
w jedną, która wykonuje wiele operacji jednocześnieRUN
powinno się czyścić wszystkie pliki tymczasowe by nie zostały zapisane w żadnej warstwie, w szczególności:
RUN
RUN
index.html
index.html
index.html
wymusi utworzenie warstwy D od nowaDockerfile
po optymalizacjiFROM ubuntu
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update -y \
&& apt-get install -y \
apache2 \
&& rm -rf /var/lib/apt/lists/*EXPOSE 80
CMD ["/usr/sbin/apachectl", "-DFOREGROUND"]
COPY index.html /var/www/html/index.html
RUN
, ale jest to podatne na błędy, które trudno i długo się naprawiaDockerfile
opisuje kilka obrazów, między którymi możemy swobodnie kopiować pliki// hello.go
package main
import "fmt"
func main() {
.Println("hello world")
fmt}
FROM golang AS builder
COPY hello.go hello.go
RUN go build hello.go
FROM ubuntu
COPY --from=builder /go/hello /usr/bin/hello
CMD /usr/bin/hello
postgres
pozwala na konfigurację wielu aspektów poprzez zmienne środowiskowe np. POSTGRESS_PASSWORD
ustala hasło administratorapostgres
pokazuje również jak wypełnić bazę danymi przy pierwszym uruchomieniudocker push
a pobieramy komendą docker pull
Istnieje kilka mechanizmów uruchamiania kontenerów, jednak najpopularniejszym jest Docker
Komenda docker run
pozwala na uruchomienie kontenera oraz konfigurację parametrów (dodatkowe zmienne środowiskowe, przekierowanie portów, itp.)
Przykładowo, jeśli pierwszy przykład na tej stronie został zbudowany jako myapache
. to uruchomienie instancji wraz z przekierowaniem portu 8080 w systemie gospodarzu do portu 80 w kontenerze można wykonać tak:
docker run --publish 8080:80 myapache
Kiedy kontener działa, można sprawdzić w przeglądarce http://localhost:8080
services
zawiera mapowanie nazw do opisów kontenerówimage
: nazwę obrazucommand
: komenda (jeśli potrzebna jest inna niż domyślna)volumes
: listę wolumenów do podłączenia podczas uruchomieniaports
: listę przekierowań portówenvironment
: listę zmiennych środowiskowychdocker-compose.yml
version: 3.9
services:
container1:
image: ubuntu
command: sleep infinity
container2:
image: ubuntu
command: sleep infinity
container1
możemy adresować drugi kontener korzystając z nazwy hosta container2
(i vice versa)Dockerfile
, która stworzy obraz kontenera systemowego z całością rozwijanego projektu: baza danych, frontend, backend (ocena 3.0)docker-compose.yml
, która uruchomi cały projekt na podstawie kontenerów aplikacyjnych (ocena 5.0)