Docker Compose: från utveckling till produktion

Översättning av podcast-transkriptionen förberedd i väntan på kursstart "Linux-administratör"

Docker Compose: från utveckling till produktion

Docker Compose är ett fantastiskt verktyg för att skapa en fungerande
miljö för den stack som används i din applikation. Det låter dig definiera
varje komponent i din applikation, enligt en tydlig och enkel syntax i YAML-
filer
.

Med tillkomsten av docker compose v3 dessa YAML-filer kan användas direkt i produktionsmiljön när man arbetar med
klunga Docker svärm.

Men betyder detta att du kan använda samma docker-compose-fil i
utvecklingsprocessen och i produktionsmiljön? Eller använd samma fil för
iscensättning? Tja, i allmänhet, ja, men för denna funktion behöver vi följande:

  • Variabelinterpolation: använder miljövariabler för vissa
    värderingar som förändras i varje miljö.
  • Konfigurationsöverstyrning: möjlighet att definiera en sekund (eller vilken som helst
    en annan efterföljande) docker-compose-fil som kommer att ändra något angående
    först, och docker compose kommer att ta hand om att slå samman båda filerna.

Skillnader mellan utvecklings- och produktionsfiler

Under utvecklingen kommer du sannolikt att vilja kontrollera kodändringar i
realtid. För att göra detta är vanligtvis volymen med källkoden monterad i
behållare som innehåller körtid för din applikation. Men för en produktionsmiljö
Denna metod är inte lämplig.

I produktionen har man ett kluster med många noder, och volymen är lokal
i förhållande till noden där din behållare (eller tjänst) körs, så det gör du inte
du kan montera källkoden utan komplexa operationer som inkluderar
kodsynkronisering, signaler osv.

Istället vill vi vanligtvis skapa en bild med en specifik version av din kod.
Det är vanligt att markera den med lämplig tagg (du kan använda semantik
versionshantering eller annat system efter eget gottfinnande).

Åsidosätt konfiguration

Med tanke på skillnaderna och att dina beroenden kan skilja sig åt i scenarier
utveckling och produktion är det klart att vi kommer att behöva olika konfigurationsfiler.

Docker compose stöder sammanslagning av olika skrivfiler till
få den slutliga konfigurationen. Hur detta fungerar kan ses i exemplet:

$ cat docker-compose.yml
version: "3.2"

services:
  whale:
    image: docker/whalesay
    command: ["cowsay", "hello!"]
$ docker-compose up
Creating network "composeconfigs_default" with the default driver
Starting composeconfigs_whale_1
Attaching to composeconfigs_whale_1
whale_1  |  ________
whale_1  | < hello! >
whale_1  |  --------
whale_1  |     
whale_1  |      
whale_1  |       
whale_1  |                     ##        .
whale_1  |               ## ## ##       ==
whale_1  |            ## ## ## ##      ===
whale_1  |        /""""""""""""""""___/ ===
whale_1  |   ~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ /  ===- ~~~
whale_1  |        ______ o          __/
whale_1  |                     __/
whale_1  |           __________/
composeconfigs_whale_1 exited with code 0

Som sagt, docker compose stöder att kombinera flera kompositioner -
filer, låter detta dig åsidosätta olika parametrar i den andra filen. Till exempel:

$ cat docker-compose.second.yml
version: "3.2"
services:
  whale:
    command: ["cowsay", "bye!"]

$ docker-compose -f docker-compose.yml -f docker-compose.second.yml up
Creating composeconfigs_whale_1
Attaching to composeconfigs_whale_1
whale_1  |  ______
whale_1  | < bye! >
whale_1  |  ------
whale_1  |     
whale_1  |      
whale_1  |       
whale_1  |                     ##        .
whale_1  |               ## ## ##       ==
whale_1  |            ## ## ## ##      ===
whale_1  |        /""""""""""""""""___/ ===
whale_1  |   ~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ /  ===- ~~~
whale_1  |        ______ o          __/
whale_1  |                     __/
whale_1  |           __________/
composeconfigs_whale_1 exited with code 0

Denna syntax är inte särskilt bekväm under utveckling, när kommandot
kommer att behöva göras många gånger.

Lyckligtvis letar docker compose automatiskt efter en speciell fil som heter
docker-compose.override.yml att åsidosätta värden docker-compose.yml. om
byt namn på den andra filen, du får samma resultat, bara med det ursprungliga kommandot:

$ mv docker-compose.second.yml docker-compose.override.yml
$ docker-compose up
Starting composeconfigs_whale_1
Attaching to composeconfigs_whale_1
whale_1  |  ______
whale_1  | < bye! >
whale_1  |  ------
whale_1  |     
whale_1  |      
whale_1  |       
whale_1  |                     ##        .
whale_1  |               ## ## ##       ==
whale_1  |            ## ## ## ##      ===
whale_1  |        /""""""""""""""""___/ ===
whale_1  |   ~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ /  ===- ~~~
whale_1  |        ______ o          __/
whale_1  |                     __/
whale_1  |           __________/
composeconfigs_whale_1 exited with code 0

Okej, det är lättare att komma ihåg.

Interpolation av variabler

Stöd för konfigurationsfiler interpolation
variabler
och standardvärden. Det vill säga, du kan göra följande:

services:
  my-service:
    build:
      context: .
    image: private.registry.mine/my-stack/my-service:${MY_SERVICE_VERSION:-latest}
...

Och om du gör det docker-compose build (eller push) utan miljövariabel
$MY_SERVICE_VERSION, kommer värdet att användas senastemen om du ställer in
värdet av miljövariabeln före byggnaden, kommer den att användas när du bygger eller pushar
till registret privat.register.min.

Mina principer

De tillvägagångssätt som fungerar för mig kan fungera för dig också. Jag följer dessa
enkla regler:

  • Alla mina stackar för produktion, utveckling (eller andra miljöer) är definierade genom
    docker-compose-filer
  • Konfigurationsfiler behövs för att täcka alla mina miljöer, så mycket som möjligt
    undvika dubbelarbete.
  • Jag behöver ett enkelt kommando för att fungera i varje miljö.
  • Huvudkonfigurationen definieras i filen docker-compose.yml.
  • Miljövariabler används för att definiera bildtaggar eller annat
    variabler som kan variera från miljö till miljö (iscenesättning, integration,
    produktion).
  • Värdena på produktionsvariabler används som värden för
    som standard minimerar detta riskerna om stacken lanseras i produktion utan
    ställ in miljövariabel.
  • För att starta en tjänst i en produktionsmiljö, använd kommandot docker stack deploy - compose-fil docker-compose.yml -with-registry-auth my-stack-name.
  • Arbetsmiljön startas med kommandot docker-komponera upp -d.

Låt oss titta på ett enkelt exempel.

# docker-compose.yml
...
services:
  my-service:
    build:
      context: .
    image: private.registry.mine/my-stack/my-service:${MY_SERVICE_VERSION:-latest}
    environment:
      API_ENDPOINT: ${API_ENDPOINT:-https://production.my-api.com}
...

И

# docker-compose.override.yml
...
services:
  my-service:
    ports: # This is needed for development!
      - 80:80
    environment:
      API_ENDPOINT: https://devel.my-api.com
    volumes:
      - ./:/project/src
...

jag kan använda docker-compose (docker-compose up)att köra stacken i
utvecklingsläge med källkod monterad i /project/src.

Jag kan använda samma filer i produktionen! Och jag skulle definitivt kunna använda
samma fil docker-compose.yml för iscensättning. För att utöka detta till
produktion behöver jag bara bygga och skicka bilden med en fördefinierad tagg
på CI-stadiet:

export MY_SERVICE_VERSION=1.2.3
docker-compose -f docker-compose.yml build
docker-compose -f docker-compose.yml push

I produktionen kan detta köras med följande kommandon:

export MY_SERVICE_VERSION=1.2.3
docker stack deploy my-stack --compose-file docker-compose.yml --with-registry-auth

Och om du vill göra samma sak på scenen behöver du bara definiera
nödvändiga miljövariabler för att arbeta i iscensättningsmiljön:

export MY_SERVICE_VERSION=1.2.3
export API_ENDPOINT=http://staging.my-api.com
docker stack deploy my-stack --compose-file docker-compose.yml --with-registry-auth

Som ett resultat använde vi två olika docker-compose-filer, vilka utan
Dubblettkonfigurationer kan användas för vilken miljö du har!

Läs mer om kursen "Linux-administratör"

Källa: will.com

Lägg en kommentar