Skip to main content
17. december 2024

Guide: Byg og kør din første dockerbaserede applikation

Læsetid: 7 minutter


Denne artikel er en dansk genudgivelse af Docker101 -> 01-intro-yourfirstimage.

Byg dit første billede

Lad os lave et simpelt Docker-billede.

Vi laver en Dockerfil til at definere vores billede. Som et basisbillede bruger vi python:3.11.0-alpine3.15.

Alpine er et letvægts-Linux-distribution, og vi vil lave en simpel python applikation for at lære om Docker-billeder og containere.

FROM python:3.11.0-alpine3.15

# Installing exta dependencies needed in our application
RUN apk update && apk add libcap
RUN pip install flask flask_bootstrap requests

# Settings some defaults
ENV GREETER DefaultGreeter

# Installing our app
WORKDIR /usr/src/app
ENV GREETER DefaultGreeter
ENV FLASK_APP app
COPY app.py app.py
COPY greetings/hello/greeting.txt /data/hello/greeting.txt

# Executed during build but really has no effect on the image (or on the running containers for that matter)
RUN echo Hello, $GREETER

# Defines what happens when the container starts
CMD { echo $GREETER; flask run --host=0.0.0.0; }

Du kan finde forskellige instruktioner på https://docs.docker.com/engine/reference/builder/ for at se detaljer og udforske flere muligheder.

Lad os bygge billedet og se resultatet af byggeprocessen:

$ docker build -t my/first:1 .
Sending build context to Docker daemon  10.75kB
Step 1/11 : FROM python:3.11.0-alpine3.15
 ---> c692f3b79c36
Step 2/11 : RUN apk update && apk add libcap
 ---> Running in 1ed0eb83cefa
fetch https://dl-cdn.alpinelinux.org/alpine/v3.15/main/x86_64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.15/community/x86_64/APKINDEX.tar.gz

... a lot of loglines related to the installation of libraries - we will ignore these for now ...

Removing intermediate container e2a85e50d99c
 ---> b22b618ca631
Step 4/11 : ENV GREETER DefaultGreeter
 ---> Running in f47db2adc718
Removing intermediate container f47db2adc718
 ---> ab16c159d28d
Step 5/11 : WORKDIR /usr/src/app
 ---> Running in 0b28af7c2c02
Removing intermediate container 0b28af7c2c02
 ---> fc5530f8fbb7
Step 6/11 : ENV GREETER DefaultGreeter
 ---> Running in 9702ab00d747
Removing intermediate container 9702ab00d747
 ---> 28de3cce1118
Step 7/11 : ENV FLASK_APP app
 ---> Running in 5eb616aa1d98
Removing intermediate container 5eb616aa1d98
 ---> d9fefb5eaa92
Step 8/11 : COPY app.py app.py
 ---> d9d6e4383100
Step 9/11 : COPY greetings/hello/greeting.txt /data/hello/greeting.txt
 ---> 91c8cf9ca83c
Step 10/11 : RUN echo Hello, $GREETER
 ---> Running in 3540464c93ae
Hello, DefaultGreeter
Removing intermediate container 3540464c93ae
 ---> 18a70c54715c
Step 11/11 : CMD { echo $GREETER; flask run --host=0.0.0.0; }
 ---> Running in 3866861588b7
Removing intermediate container 3866861588b7
 ---> 0045bdbc0751
Successfully built 0045bdbc0751
Successfully tagged my/first:1

Hver instruktionslinje i Dockerfilen tilføjer et ‘lag’ i filsystemet på det færdige billede. Resultatet af ‘Hello, DefaultGreeter’ viser, hvordan udførelsen af ‘echo’-kommandoen er en del af byggefasen. Det vil ikke have effekt på det færdige billede, eftersom det ikke tilføjer/fjerner noget i lagene.

Kør billedet

Lad os prøve at køre billedet:

$ docker run my/first:1
DefaultGreeter
 * Serving Flask app 'app'
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on all addresses (0.0.0.0)
 * Running on http://127.0.0.1:5000
 * Running on http://172.17.0.2:5000
Press CTRL+C to quit

Nu kører containeren. Du kan se alle dine kørende containere:

$ docker ps
CONTAINER ID   IMAGE        COMMAND                  CREATED         STATUS         PORTS     NAMES
7a13fa1e44be   my/first:1   "/bin/sh -c '{ echo …"   5 seconds ago   Up 4 seconds             fervent_murdock

Dockermotoren definerer et Docker-netværk. Hver container får en IP-adresse i dette netværk.

Vi kan ikke nå slutpunktet for den kørende container fra vores værtsmaskine uden at definere en portmapping.

Lad os køre med en portmapping:

$ docker run -p 5000:5000 my/first:1
DefaultGreeter
 * Serving Flask app 'app'
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on all addresses (0.0.0.0)
 * Running on http://127.0.0.1:5000
 * Running on http://172.17.0.2:5000
Press CTRL+C to quit


$ docker ps
CONTAINER ID   IMAGE        COMMAND                  CREATED         STATUS         PORTS                                       NAMES
94cfbde47286   my/first:1   "/bin/sh -c '{ echo …"   8 seconds ago   Up 7 seconds   0.0.0.0:5000->5000/tcp, :::5000->5000/tcp   competent_lamport

Læg mærke til, at vi nu har en mapping over port 5000 på værtsmaskinen til port 5000 på den kørende docker container.
Vi kan nu nå vores applikation fra vores værtsmaskine.

$ curl http://localhost:5000/hello 
Hi - From DefaultGreeter

Vi kan levere konfiguration ved kørsel ved at bruge miljøvariabler:

$ docker run -e GREETER=RunningGreeter -p 5000:5000 -t my/first:1
RunningGreeter
 * Serving Flask app 'app'
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on all addresses (0.0.0.0)
 * Running on <a href="http://127.0.0.1:5000" target="_blank" rel="noopener">http://127.0.0.1:5000</a>
 * Running on <a href="http://172.17.0.2:5000" target="_blank" rel="noopener">http://172.17.0.2:5000</a>
Press CTRL+C to quit

$ curl http://localhost:5000/hello
Hi - From RunningGreeter

$ curl http://localhost:5000/birthday
&lt;!doctype html&gt;
&lt;html lang=en&gt;
&lt;title&gt;500 Internal Server Error&lt;/title&gt;
&lt;h1&gt;Internal Server Error&lt;/h1&gt;
&lt;p&gt;The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.&lt;/p&gt;

Bemærk hvordan greeter-navnet er ændret med vores nye definition af miljøvariablen GREETER. Hvis vi prøver at få adgang til fødselsdags-URL’en, vil applikationen give os en fejl.

Vi kan også levere konfiguration ved kørsel ved at bruge volumen-mounts (montere filer i filsystemet på den kørende container):

$ docker run -e GREETER=RunningGreeter -p 5000:5000 -v $(pwd)/greetings/birthday:/data/birthday my/first:1
RunningGreeter
 * Serving Flask app 'app'
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on all addresses (0.0.0.0)
 * Running on http://127.0.0.1:5000
 * Running on http://172.17.0.2:5000
Press CTRL+C to quit

$ curl http://localhost:5000/birthday
Happy Birthday - From RunningGreeter

Vores Python-applikation tillader konfiguration af forskellige hilsner ved brug af volumen-mounts.

Den er faktisk også sårbar over for et alvorligt problem – kan du se hvordan?

Hint: URL-kod ‘hello; echo Shell Injections are nasty; cat /data/hello’

Hvis du vil læse mere som dette, kan der findes flere tekster på https://github.com/KvalitetsIT.

Forfatter

Headline

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Headline