NLEN
Direct technisch advies?
Home > Blog

How to Postgres on Docker deel 2 van 3

Craig Healey 25-9-2019 14:32
Categorieën: BLOG, Cloud, PostgreSQL, Technisch, Tips

In mijn vorige blogpost heb ik laten zien hoe je postgreSQL in een Docker-container kunt instellen, tot het punt waar je de database met psql of pgAdmin kon beheren. Ik had echter nog niet uitgelegd hoe het werkt. Als je iets anders probeert te doen, zelfs iets kleins, of als je fouten tegenkomt zoals ik heb geschetst, dan moet je weten wat al die commando's eigenlijk doen.

In deze blog leg ik je dat uit.

Docker is een verzameling van producten waarmee software in gevirtualiseerde omgevingen (containers), uitgevoerd wordt. Op Windows draaien die Docker-containers normaal gesproken in een VirtualBox. Docker maakt die VirtualBoxes aan tijdens de eerste uitvoering. De laatste keer hebben we een container gemaakt met de naam "some-postgres".

Maar waar halen we de software vandaan om een container te maken - het besturingssysteem en PostgreSQL?

Herinner je de image van de vorige blogpost (How to Postgres on Docker deel 1 van 3) op de Docker Hub genaamd Postgres? Laten we eens kijken naar de opdracht die is gebruikt om de container te maken:

Docker runDe meeste Docker commando's beginnen met het trefwoord Docker.

docker run --help

geeft je een lijst met de mogelijke opties oftewel flags.

Met de opdracht *run wordt een container gemaakt.

De flag *--name definieert een naam. Containers zijn bijzonder in Docker. Als je ze geen naam geeft, krijgen ze een standaardnaam, zoals angry_davinci, jolly_wing of tender_banach. Voor de meeste andere Docker-objecten geldt dat als je geen naam opgeeft, Docker een hash-key zal genereren en die vervolgens gebruiken. In dit geval heb ik "some-postgres" gebruikt, zoals voorgesteld op de postgres Hub-pagina.

Poorten

De volgende flag definieert de poort van de container. Alle flags hebben een naam met meerdere tekens voorafgegaan door 2 streepjes (POSIX-standaard), maar sommige flags hebben ook een alias die uit één teken bestaat. Ik had dus kunnen gebruiken *-p 5432:5432 of *--publish 5432:5432. Het eerste nummer staat voor de externe- en het tweede - voor de interne poort.

De default poort voor PostgreSQL-servers is 5432. Dus als we meerdere PostgreSQL-containers maken die op de defaultpoort draaien (wat we hierna gaan doen), moeten we ze verschillende externe poorten opgeven. Als ik 3 van dergelijke containers wilde maken die allemaal tegelijkertijd vanuit pgAdmin konden worden benaderd, zou ik de volgende flags gebruiken:

-p 5432:5432

-p 5433:5432

-p 5434:5432 

On pgAdmin, zou ik 3 servers creeëren met de poorten 5432, 5433 en 5434.

De volgende flag, *-e of *--env, somt omgevingsvariabelen op die specifiek zijn voor de image. In dit geval willen we het postgres-gebruikerswachtwoord instellen zodat we via pgAdmin verbinding kunnen maken. Als een image dergelijke variabelen moet instellen, moeten ze ergens vermeld zijn. In het geval van deze PostgreSQL-image zijn ze halverwege de inleidende pagina gedetailleerd uitgelegd: 

De laatste flag is *-d of *--detach, waarmee we aangegeven dat de container op de achtergrond wordt uitgevoerd. Vergeet je dit en voer je het commando uit, dan kom je rechtstreeks in de container en als je weggaat, stopt de container.

Ten slotte wordt de naam van de afbeelding opgegeven, in dit geval postgres. Direct na de afbeeldingsnaam kun je een lijst met de opdrachten opgeven die de container gaat uitvoeren, maar in dit geval hoeven we dat niet te doen. 

Dockerfile

Het op deze manier opspinnen van containers geeft je niet veel controle, vooral omdat Docker de automatisering zou moeten verbeteren in plaats van de typevaardigheden. De normale manier om Docker uit te voeren is een proces in drie stappen. Eerst maakt u een tekstbestand, zogenaamd een Dockerbestand, bestaande uit een basisimage.

De basisimage zit als eerste in het Docker-bestand (je kunt ook de opmerkingen hebben, beginnend met #) en wordt voorafgegaan door het trefwoord FROM. Er is een speciale basisimage, genaamd scratch, die helemaal niets bevat. Dus, om je eigen image zelf te bouwen, zal de eerste regel van je Dockerbestand zijn:

FROM scratch

Hierna kun je alles aan je image toevoegen wat je maar wilt. Maar je hoeft niet helemaal opnieuw te beginnen. Je kan de bestaande image uitbreiden. Je kan een ubuntu-image met specifieke tools en variabelen instellen. Hierna kun je andere images maken door de verschillende versies van PostgreSQL op exact hetzelfde onderliggende besturingssysteem te installeren. Dat stelt je in staat om alleen de verschillen in PostgreSQL-versies te testen. Met behulp van het Docker-bestand bouwt je je eigen image op, net zoals die je uit de Docker-hub kunt halen. En met die image kun je een container draaien.

Images

Wij gaan een image maken op basis van de postgres-image waar we de vorige keer naar gekeken hebben. Maak een tekstbestand met de naam "Dockerfile". Docker zoekt standaard naar het Docker-bestand in de huidige werkmap (genaamd de build-context). Natuurlijk kan je Docker-opdrachten uitvoeren vanuit een command prompt of PowerShell-window, niet uitsluitend vanuit het Docker Terminal-programma. Je kunt je Docker-bestanden in elke gewenste map opslaan, gebruik gewoon de flag *-f om de bestandslocatie op te geven. Om het mezelf makkelijk te maken, maak ik een testmap in de Docker Toolbox-map. Vergeet niet dat je Linux-opdrachten moet gebruiken wanneer je je in het Terminal-venster bevindt. Dus, ls in plaats van dir, en pwd in plaats van echo %cd%. Je hebt ook toegang tot vi-editor als je wilt. Mijn Dockerfile bestaat uit slechts 2 regels:

FROM postgres

ENV POSTGRES_PASSWORD=mysecretpassword

Om het image aan te maken, type

docker build -t craig/postgres:version1 .

Vergeet niet de full stop (punt) aan het eind. Dat geeft Docker opdracht om het "Dockerfile"-bestand in de huidige directory te gebruiken. 

Docker buildJe kunt zien dat de build is een proces in twee stappen. Eerst wordt het basisimage gevonden. Als het al is gedownload, zoals hier, gaat het verder met de volgende stap, anders wordt het voor je uit de Docker Hub gehaald. Vervolgens wordt de volgende opdrachtregel toegevoegd, in dit geval is dit het POSTGRES_PASSWORD. Het betreft een tijdelijke container, die automatisch voor je wordt verwijderd. Nadat de build is voltooid en de image een image-ID heeft gekregen, krijg je een beveiligingswaarschuwing. Dat is belangrijk als je overweegt om dit voor een real-life systeem te doen, maar voor nu kun je het veilig negeren. Als ik versie 2 van het image bouw zonder het Docker bestand te bouwen, is Docker slim genoeg om te weten dat er niets hoeft te worden gewijzigd. Een nieuwe image wordt gemaakt, genaamd craig / postgres: version 2, maar de afbeelding-ID zal hetzelfde zijn als voor craig / postgres: version 1. Je ziet hier de mogelijkheid om meerdere afhankelijkheden te maken. Helaas is er geen gemakkelijke methode om afhankelijkheden te weergeven afgezien van third-party scripts and tools. Het dichtst in de buurt van een Docker-opdracht komt:

docker inspect --format='{{.Id}} {{.Parent}} {{.RepoTags}}' $(docker images -quiet)

Docker inspectDit geeft weer de sha256 van een image (waarvan de eerste 12 cijfers worden gebruikt als de image-ID), gevolgd door de eventuele bovenliggende image, zo die er is. Voor meer informatie over de opmaak van dit commando zie deze blog.

Als het tijd is om een images te verwijderen, kunt je dit niet doen als deze een onderliggende image heeft, dus kun je wellicht hier gebruik van maken om images te verwijderen die je niet langer nodig hebt. Je kan ook gebruiken: 

docker history postgres

Docker history postgresdie een overzicht geeft van alle commando's die worden gebruikt om een image aan te maken, alle images die zijn gecreeërd en de omvang van iedere individuele stap.

Om alle images op onze machine te weergeven, gebruik het *docker image ls commando:

docker image ls

docker image lsHier vallen een aantal dingen op. Allereerst de naamgevingsconventie. Images worden vaak opgeslagen in registers (Docker heeft zelfs een eigen registerimage), je gebruikt git-achtige opdrachten om images naar de registers te trekken en te pushen. Het eerste deel van de naam is de registerhostnaam. Als je een account bij Docker Hub hebt, is dat je registerhostnaam wanneer je de image pusht. Sommige images hebben geen registerhostnaam, het zijn meestal officiële images. Het gedeelte achter de schuine streep is de naam van de image. En ten slotte kun je met een tag verschillende versies van een image markeren.

Omdat ik niet van plan ben deze images naar een register te pushen, volg ik alleen de naamgevingsconventie om alles netjes te houden. Merk op dat de officiële postgres-image is als laatste getagd. Als je bij het samenstellen van de image geen tag opgeeft, wordt de laatste toegevoegd. Ik heb geen tag opgegeven voor de postgres-image in mijn Dockerfile, dus de laatste is gebruikt. Als ik een eerdere versie van PostgreSQL wil, kan ik opgeven:

FROM postgres:9.6

en het zal die versie van postgres uit de Docker Hub halen. Natuurlijk ga ik ervan uit dat postgres: 9.6 een container is die is gebouwd met PostgreSQL v9.6, maar omdat het een officiële image is, is dat een redelijk veilige gok. Je kunt meestal de tags controleren op het Docker Hub-pagina van de door jou gebruikte image. Als ik wil, kan ik ook kijken naar de metagegevens voor de image die ik heb binnen getrokken (of alle andere Docker-object op mijn machine) met behulp van het *docker inspect commando. Gebruik eerst:

docker pull postgres:9.6

om de specifiek postgres image te halen uit de Docker Hub. Voer dan uit:

docker inspect postgres:9.6

en je zult zien een groot JSON document.

Als ik een andere image maak die dezelfde versie van postgres gebruikt, gaat Docker deze niet opnieuw downloaden, hij gebruikt de image die hij heeft. Als ik zowel de standaard postgres-image als versie 9.6 gebruik, haalt Docker ook de oudere image op waarna ik postgres:laatste en postgres:9.6 op mijn computer opgeslagen heb. Als je een aantal images aanmaakt, hou dan in de gaten hoeveel ruimte VirtualBox standaard gebruikt, want daar worden ze opgeslagen. Sommige images zijn gebouwd met een minimum aan tools om zo licht mogelijk te zijn. De nieuwste postgres-image is v11. Als ik een postgres v11-image haal die is gebouwd op Alpine Linux:

docker pull postgres:11-alpine

en vergelijk dan de omvang:

docker image ls

docker image ls

Je ziet dat de laatste versie 313 Mb groot is, de 9.6 versie is 230 Mb en de lichtgewicht 11-alpine versie is 71.9 Mb. Dit is dus ook iets om mee te nemen bij het bouwen van je eigen images.

Volumes

Docker-containers worden verondersteld kortstondig te zijn en op elk moment automatisch te kunnen worden aangemaakt en verwijderd. Maar als je container een database is, wat gebeurt er dan met de data? Je kunt permanente gegevensvolumes maken die zich op de VirtualBox-machine bevinden en die toegankelijk zijn voor containers die op de juiste manier zijn gemaakt.

Volumes zijn onafhankelijk van images en containers, dus je kunt hetzelfde volume voor meerdere containers gebruiken, zelfs tegelijkertijd. Helaas is het onderhouden van Volumes in Docker niet zo eenvoudig als het zou moeten zijn. In tegenstelling tot Containers krijgen Volumes niet automatisch een naam en omdat het eenvoudig is om een Volume te maken zonder dat je het merkt, kunt je met veel mysterieus genoemde Volumes eindigen en geen idee hebben waar ze worden gebruikt. Om dat probleem te voorkomen, kun je expliciet een volume maken en benoemen voordat je het met een container gebruikt:

docker volume create postgres_vol_1

Je kunt ook de flag *-v gebruiken en een naam opgeven voor het volume wanneer je de container runt en deze toewijst aan de map, bijvoorbeeld:

docker run -v postgres_vol_2:/var/lib/postgresql/data --name volume-postgres -p 5433:5432 -d craig/postgres:version1 

The /var/lib/postgresql/data directory is de standaard data directory voor PostgreSQL als je gebruik maakt van de Official Image, zoals dat wordt besproken bij de How to extend this image sectie van hun Docker Hub-pagina.

Als je beide bovenstaande commando's hebt uitgevoerd, en je typt:

docker volume ls 

docker volume lsdan zie je 3 volumes: een default met een lange alfanumerieke waarde in de naam, en 2 postgres_vol volumes. Als alleen postgres_vol_2 wordt gebruikt, dan kun je postgres_vol_1 verwijderen:

docker volume rm postgres_vol_1

Let op, want:

docker system prune

verwijdert Volumes niet. Je dient het volgende commando te gebruiken:

docker volume prune

of:

docker volume rm 

Als het Volume een ID heeft in plaats van een naam, moet je de volledige naam intypen. Andere commando's werken wel met een gedeeltelijke ID dat uniek is, maar deze niet.

Networks

Docker maakt standaard 3 netwerken aan, die u kunt zien met behulp van

docker network ls 

docker network ls

  • Bridge - het netwerk waarin de containers standaard draaien. De Docker bridge driver installeert op de machine de regels zodat de containers op andere brigde-netwerken met elkaar niet kunnen communiceren.
  • Host - gebruikt directe netwerk van de host
  • None - zet alle netwerken uit.

Om je eigen netwerk aan te maken zodat de containers geïsoleerd worden van de containers die niet in hetzelfde netwerk zitten, gebruik 

docker network create --driver bridge my_bridge_network

Voeg de flag *--network my_bridge_network toe als je een container aanmaakt. Er is nog veel meer te zeggen over de netwerken in Docker maar omdat dit een database blog is, wil ik je verwijzen naar Networking tutorial van Docker. 

Docker-machine

Laten we ten slotte kort kijken naar een van de tools die bij Docker wordt geleverd, namelijk Docker Machine. Met Docker Machine kun je onder andere een virtuele machine met Docker erop maken en besturen. Bekijk het volledige overzicht op official pages. Maar voor nu kijken we alleen naar het maken en verwijderen van een VirtualBox-machine. Geef eerst de machines weer die je al hebt, in dit geval alleen default:

docker-machine ls

docker machine ls

Maak dan een nieuw machine genaamd "virtual-docker":

docker-machine create virtual-docker

Na even wachten zou het klaar moeten zijn:

docker-machine create virtual-dockerToon de machines opnieuw, gebruik:

docker-machine ls

docker machine lsMerk op dat default machine als actief wordt weergegeven. Iedere Docker-commando die je gebruikt, wordt op die machine uitgevoerd. Je kunt het testen door containers die worden gebruikt te tonen:

docker ps

Verander nu de machine door de DOCKER_HOST variabele aan te passen naar een URL van de "virtual-docker"-machine, in mijn geval is dat 192.168.99.111:2376:

DOCKER_HOST=tcp://192.168.99.111:2376

Toon opnieuw de docker machines en de actieve containers:

docker-machine ls
docker ps


docker psJe kunt zien dat "virtual-docker" wordt nu weergegeven als actieve machine en dat er geen containers aanwezig zijn. Verder kun je ook de VirtualBox Manager openen en zien dat een nieuwe machine actief is. Alle docker commando's die je nu typt, worden uitgevoerd op de "virtual-docker"-machine. Om de standaard machine te activeren en de "virtual-docker"-machine te verwijderen, gebruik:

DOCKER_HOST=tcp://192.168.99.105:2376

docker-machine rm virtual-docker

Zoals met alle commando's kun je meer informatie vinden door de flag *--help te gebruiken.

Dit was een behoorlijk uitgebreid blog. In het derde en laatste deel van deze blog serie zal ik aandacht schenken aan het opleveren van een PostgreSQL cluster, zowel de gemakkelijke manier (gebaseerd op het werk van een ander) als het echte werk (door het zelf te doen).

Deel 1 gemist?

How to Postgres on Docker deel 1 van 3

How to Postgres on Docker deel 3 van 3

Route naar effectief databasebeheer?

Wat is nu de route naar effectief databasebeheer? Wat zijn de valkuilen ? Om een aantal handvatten aan te reiken hebben we daar een whitepaper over geschreven.

Download whitepaper

Terug naar blogoverzicht

 



 

Reageer