Zelfstudie: Gegevens in een container-app behouden met behulp van volumes in VS Code

In deze zelfstudie leert u hoe u gegevens in een containertoepassing kunt behouden. Wanneer u deze uitvoert of bijwerkt, zijn de gegevens nog steeds beschikbaar. Er zijn twee hoofdtypen volumes die worden gebruikt om gegevens te behouden. Deze tutorial richt zich op benoemde volumes.

U leert ook over bindingskoppelingen, waarmee het exacte koppelpunt op de host wordt bepaald. U kunt bind-mounts gebruiken om gegevens vast te houden, maar daarmee kan ook meer data in containers worden toegevoegd. Wanneer u aan een toepassing werkt, kunt u een bindingskoppeling gebruiken om broncode te koppelen aan de container om codewijzigingen te zien, te reageren en de wijzigingen meteen te zien.

In deze zelfstudie maakt u ook kennis met laagopslag van afbeeldingen, laagcaching en builds met meerdere fasen.

In deze zelfstudie leert u het volgende:

  • Begrijp gegevens in containers.
  • Gegevens behouden met behulp van benoemde volumes.
  • Gebruik bindingskoppelingen.
  • Afbeeldingslaag weergeven.
  • Cacheafhankelijkheden.
  • Begrijp builds met meerdere fasen.

Voorwaarden

Deze zelfstudie gaat verder met de vorige zelfstudie: Een container-app maken en delen met Visual Studio Code. Begin met die ene, die de vereisten bevat.

Inzicht in gegevens in containers

In deze sectie start u twee containers en maakt u er een bestand in. De bestanden die in de ene container zijn gemaakt, zijn niet beschikbaar in een andere container.

  1. Start een ubuntu container met behulp van deze opdracht:

    docker run -d ubuntu bash -c "shuf -i 1-10000 -n 1 -o /data.txt && tail -f /dev/null"
    

    Deze opdracht start en roept twee opdrachten aan met behulp van &&. Het eerste gedeelte kiest één willekeurig getal en schrijft het naar /data.txt. Met de tweede opdracht wordt een bestand bekeken om de container actief te houden.

  2. Klik in VS Code in Container Explorer met de rechtermuisknop op de Ubuntu-container en selecteer Shell koppelen.

    Schermopname van de extensie Container Tools met een container geselecteerd en een contextmenu met Attach Shell geselecteerd.

    Er wordt een terminal geopend waarop een shell wordt uitgevoerd in de Ubuntu-container.

  3. Voer de volgende opdracht uit om de inhoud van het bestand /data.txt te bekijken.

    cat /data.txt
    

    De terminal toont een getal tussen 1 en 10000.

    Als u de opdrachtregel wilt gebruiken om dit resultaat te zien, haalt u de container-id op met behulp van de opdracht docker ps en voert u de volgende opdracht uit.

    docker exec <container-id> cat /data.txt
    
  4. Start een andere ubuntu container.

    docker run -d ubuntu bash -c "shuf -i 1-10000 -n 1 -o /data.txt && tail -f /dev/null"
    
  5. Gebruik deze opdracht om de inhoud van de map te bekijken.

    docker run -it ubuntu ls /
    

    Er mag geen data.txt-bestand zijn omdat het naar de tijdelijke ruimte is geschreven voor alleen de eerste container.

  6. Selecteer deze twee Ubuntu-containers. Klik met de rechtermuisknop en selecteer verwijderen. Vanaf de opdrachtregel kunt u ze verwijderen met behulp van de opdracht docker rm -f.

Persisteer uw to-do-lijst gegevens door gebruik te maken van benoemde volumes

De to-do-app slaat de gegevens standaard op in een SQLite-database op /etc/todos/todo.db. SQLite Database is een relationele database waarin gegevens één bestand worden opgeslagen. Deze aanpak werkt voor kleine projecten.

U kunt het enkele bestand op de host behouden. Wanneer u deze beschikbaar maakt voor de volgende container, kan de toepassing ophalen waar deze was gebleven. Door een volume te maken en te koppelen, of te monteren, aan de map waarin de gegevens zijn opgeslagen, kunt u de gegevens behouden. De container schrijft naar het todo.db-bestand en die gegevens blijven behouden op de host in het volume.

Gebruik voor deze sectie een met de naam volume. Docker onderhoudt de fysieke locatie van het volume op de schijf. Raadpleeg de naam van het volume en Docker biedt de juiste gegevens.

  1. Maak een volume met behulp van de opdracht docker volume create.

    docker volume create todo-db
    
  2. Selecteer onder CONTAINERSgetting-started en klik met de rechtermuisknop. Selecteer Stop om de app-container te stoppen.

    Om de container via de commandoregel te stoppen, gebruikt u de opdracht docker stop.

  3. Start de container getting-started met behulp van het volgende commando.

    docker run -dp 3000:3000 -v todo-db:/etc/todos getting-started
    

    De volumeparameter geeft het volume aan dat moet worden gekoppeld en de locatie, /etc/todos.

  4. Vernieuw uw browser om de app opnieuw te laden. Als u het browservenster hebt gesloten, gaat u naar http://localhost:3000/. Voeg enkele items toe aan uw takenlijst.

    Schermopname toont de voorbeeld-app met verschillende items die aan de lijst zijn toegevoegd.

  5. Verwijder de getting-started container voor de to-do app. Klik met de rechtermuisknop op de container in Container Explorer en selecteer Verwijderen of gebruik de docker stop en docker rm opdrachten.

  6. Start een nieuwe container met dezelfde opdracht:

    docker run -dp 3000:3000 -v todo-db:/etc/todos getting-started
    

    Met dit commando wordt hetzelfde station gekoppeld als voorheen. Vernieuw uw browser. De items die u hebt toegevoegd, bevinden zich nog steeds in uw lijst.

  7. Verwijder de aan de slag container opnieuw.

Benoemde volumes en bind mounts, die hieronder worden besproken, zijn de belangrijkste typen volumes die worden ondersteund door de installatie van de standaard Docker-engine.

Eigenschap Benoemde volumes Bindingskoppelingen
Hostlocatie Docker kiest U bepaalt
Voorbeeld van montage (met behulp van -v) my-volume:/usr/local/data /path/to/data:/usr/local/data
Vult een nieuw volume met de inhoud van de container Ja Nee
Ondersteunt volumestuurprogramma's Ja Nee

Er zijn veel invoegtoepassingen voor volumestuurprogramma's beschikbaar ter ondersteuning van NFS, SFTP, NetApp en meer. Deze invoegtoepassingen zijn vooral belangrijk voor het uitvoeren van containers op meerdere hosts in een geclusterde omgeving, zoals Swarm of Kubernetes.

Als u zich afvraagt waar Docker daadwerkelijk uw gegevens opslaat, voert u de volgende opdracht uit.

docker volume inspect todo-db

Kijk naar de output, die vergelijkbaar is met dit resultaat.

[
    {
        "CreatedAt": "2019-09-26T02:18:36Z",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/todo-db/_data",
        "Name": "todo-db",
        "Options": {},
        "Scope": "local"
    }
]

De Mountpoint is de werkelijke locatie waar de gegevens worden opgeslagen. Op de meeste computers hebt u hoofdtoegang nodig om toegang te krijgen tot deze map vanaf de host.

Bind mounts gebruiken

Met bind-mountskunt u het exacte koppelpunt op de host bepalen. Deze aanpak houdt gegevens vast, maar wordt vaak gebruikt om meer gegevens in containers te leveren. U kunt een bindingskoppeling gebruiken om broncode in de container te koppelen, codewijzigingen te laten zien, erop te reageren en u de wijzigingen meteen te laten zien.

Als u uw container wilt uitvoeren ter ondersteuning van een ontwikkelwerkstroom, voert u de volgende stappen uit:

  1. Verwijder de getting-started-containers.

  2. Voer in de map app de volgende opdracht uit.

    docker run -dp 3000:3000 -w /app -v ${PWD}:/app node:lts-alpine sh -c "yarn install && yarn run dev"
    

    Deze opdracht bevat de volgende parameters.

    • -dp 3000:3000 Hetzelfde als voorheen. Voer deze uit in de losgekoppelde modus en maak een poorttoewijzing.
    • -w /app werkmap in de container.
    • -v ${PWD}:/app" Bind koppelt de huidige map van de host in de container aan de /app map.
    • node:lts-alpine de te gebruiken afbeelding. Deze afbeelding is de basisafbeelding voor uw app uit de Dockerfile.
    • sh -c "yarn install && yarn run dev" A-opdracht. Er wordt een shell gestart met sh en yarn install wordt uitgevoerd om alle afhankelijkheden te installeren. Vervolgens wordt yarn run devuitgevoerd. Als u in de package.jsonkijkt, is het dev script aan het starten nodemon.
  3. U kunt de logboeken bekijken met behulp van docker logs.

    docker logs -f <container-id>
    
    $ nodemon src/index.js
    [nodemon] 2.0.20
    [nodemon] to restart at any time, enter `rs`
    [nodemon] watching path(s): *.*
    [nodemon] watching extensions: js,mjs,json
    [nodemon] starting `node src/index.js`
    Using sqlite database at /etc/todos/todo.db
    Listening on port 3000
    

    Wanneer u de laatste vermelding in deze lijst ziet, is de app actief.

    Wanneer u klaar bent met het bekijken van de logboeken, selecteert u een willekeurige toets in het terminalvenster of selecteert u Ctrl+C- in een extern venster.

  4. Open in VS Code src/static/js/app.js. Wijzig de tekst van de knop Item toevoegen op regel 109.

    - {submitting ? 'Adding...' : 'Add Item'}
    + {submitting ? 'Adding...' : 'Add'}
    

    Sla uw wijziging op.

  5. Vernieuw uw browser. U ziet de wijziging.

    Schermopname toont de voorbeeld-app met de nieuwe tekst op de knop.

  6. Verwijder de node:lts-alpine container.

  7. Voer in de app map de volgende opdracht uit om de node_modules map te verwijderen die in de vorige stappen is gemaakt.

    rm -r node_modules
    

Afbeeldingslagen weergeven

U kunt de lagen bekijken waaruit een afbeelding bestaat. Voer de opdracht docker image history uit om de opdracht te zien die is gebruikt om elke laag in een afbeelding te maken.

  1. Gebruik docker image history om de lagen te zien in de 'getting-started' afbeelding die u eerder in de zelfstudie hebt gemaakt.

    docker image history getting-started
    

    Het resultaat zou vergelijkbaar moeten zijn met dit voorbeeld.

    IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
    a78a40cbf866        18 seconds ago      /bin/sh -c #(nop)  CMD ["node" "/app/src/ind…   0B                  
    f1d1808565d6        19 seconds ago      /bin/sh -c yarn install --production            85.4MB              
    a2c054d14948        36 seconds ago      /bin/sh -c #(nop) COPY dir:5dc710ad87c789593…   198kB               
    9577ae713121        37 seconds ago      /bin/sh -c #(nop) WORKDIR /app                  0B                  
    b95baba1cfdb        13 days ago         /bin/sh -c #(nop)  CMD ["node"]                 0B                  
    <missing>           13 days ago         /bin/sh -c #(nop)  ENTRYPOINT ["docker-entry…   0B                  
    <missing>           13 days ago         /bin/sh -c #(nop) COPY file:238737301d473041…   116B                
    <missing>           13 days ago         /bin/sh -c apk add --no-cache --virtual .bui…   5.35MB              
    <missing>           13 days ago         /bin/sh -c #(nop)  ENV YARN_VERSION=1.21.1      0B                  
    <missing>           13 days ago         /bin/sh -c addgroup -g 1000 node     && addu…   74.3MB              
    <missing>           13 days ago         /bin/sh -c #(nop)  ENV NODE_VERSION=12.14.1     0B                  
    <missing>           13 days ago         /bin/sh -c #(nop)  CMD ["/bin/sh"]              0B                  
    <missing>           13 days ago         /bin/sh -c #(nop) ADD file:e69d441d729412d24…   5.59MB   
    

    Elk van de lijnen vertegenwoordigt een laag in de afbeelding. De uitvoer toont de basis onderaan met de nieuwste laag bovenaan. Met behulp van deze informatie kunt u de grootte van elke laag zien, zodat u grote afbeeldingen kunt diagnosticeren.

  2. Verschillende regels zijn afgekapt. Als u de parameter --no-trunc toevoegt, krijgt u de volledige uitvoer.

    docker image history --no-trunc getting-started
    

Cacheafhankelijkheden

Zodra een laag is gewijzigd, moeten ook alle downstreamlagen opnieuw worden gemaakt. Hier ziet u de Dockerfile opnieuw:

FROM node:lts-alpine
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "/app/src/index.js"]

Elke opdracht in het Dockerfile wordt een nieuwe laag in de image. Als u het aantal lagen wilt minimaliseren, kunt u uw Dockerfile- herstructureren om caching van afhankelijkheden te ondersteunen. Voor node-gebaseerde toepassingen worden deze afhankelijkheden gedefinieerd in het package.json-bestand.

De methode is om alleen dat bestand eerst te kopiëren, de afhankelijkheden te installeren en vervolgens vervolgens alles kopiëren. Het proces maakt alleen de yarn-afhankelijkheden opnieuw als er een wijziging is aangebracht in de package.json.

  1. Werk de Dockerfile- bij om eerst in de package.json te kopiëren, afhankelijkheden te installeren en vervolgens alles te kopiëren. Dit is het nieuwe bestand:

    FROM node:lts-alpine
    WORKDIR /app
    COPY package.json yarn.lock ./
    RUN yarn install --production
    COPY . .
    CMD ["node", "/app/src/index.js"]
    
  2. Bouw een nieuwe afbeelding met behulp van docker build.

    docker build -t getting-started .
    

    Als het goed is, ziet u uitvoer zoals de onderstaande resultaten:

    Sending build context to Docker daemon  219.1kB
    Step 1/6 : FROM node:lts-alpine
    ---> b0dc3a5e5e9e
    Step 2/6 : WORKDIR /app
    ---> Using cache
    ---> 9577ae713121
    Step 3/6 : COPY package* yarn.lock ./
    ---> bd5306f49fc8
    Step 4/6 : RUN yarn install --production
    ---> Running in d53a06c9e4c2
    yarn install v1.17.3
    [1/4] Resolving packages...
    [2/4] Fetching packages...
    info fsevents@1.2.9: The platform "linux" is incompatible with this module.
    info "fsevents@1.2.9" is an optional dependency and failed compatibility check. Excluding it from installation.
    [3/4] Linking dependencies...
    [4/4] Building fresh packages...
    Done in 10.89s.
    Removing intermediate container d53a06c9e4c2
    ---> 4e68fbc2d704
    Step 5/6 : COPY . .
    ---> a239a11f68d8
    Step 6/6 : CMD ["node", "/app/src/index.js"]
    ---> Running in 49999f68df8f
    Removing intermediate container 49999f68df8f
    ---> e709c03bc597
    Successfully built e709c03bc597
    Successfully tagged getting-started:latest
    

    Alle lagen zijn herbouwd. Dit resultaat wordt verwacht omdat u de Dockerfilehebt gewijzigd.

  3. Breng een wijziging aan in de src/static/index.html. Wijzig bijvoorbeeld de titel in 'The Awesome Todo App'.

  4. Bouw de Docker-image nu opnieuw met docker build. Deze keer moet uw uitvoer er iets anders uitzien.

    Sending build context to Docker daemon  219.1kB
    Step 1/6 : FROM node:lts-alpine
    ---> b0dc3a5e5e9e
    Step 2/6 : WORKDIR /app
    ---> Using cache
    ---> 9577ae713121
    Step 3/6 : COPY package* yarn.lock ./
    ---> Using cache
    ---> bd5306f49fc8
    Step 4/6 : RUN yarn install --production
    ---> Using cache
    ---> 4e68fbc2d704
    Step 5/6 : COPY . .
    ---> cccde25a3d9a
    Step 6/6 : CMD ["node", "/app/src/index.js"]
    ---> Running in 2be75662c150
    Removing intermediate container 2be75662c150
    ---> 458e5c6f080c
    Successfully built 458e5c6f080c
    Successfully tagged getting-started:latest
    

    Omdat u de buildcache gebruikt, moet deze veel sneller gaan.

Builds met meerdere fasen

Builds met meerdere fasen zijn een ongelooflijk krachtig hulpmiddel waarmee u meerdere fasen kunt gebruiken om een installatiekopie te maken. Er zijn verschillende voordelen voor hen:

  • Afhankelijkheden van de buildtijd scheiden van runtime-afhankelijkheden
  • Verklein de totale grootte van de installatiekopie door alleen te verzenden wat uw app nodig heeft om uit te voeren

Deze sectie bevat korte voorbeelden.

Maven/Tomcat-voorbeeld

Wanneer u op Java gebaseerde toepassingen bouwt, is een JDK nodig om de broncode te compileren naar Java-bytecode. De JDK is niet nodig in productie. Mogelijk gebruikt u hulpprogramma's zoals Maven of Gradle om de app te bouwen. Deze hulpprogramma's zijn ook niet nodig in uw uiteindelijke afbeelding.

FROM maven AS build
WORKDIR /app
COPY . .
RUN mvn package

FROM tomcat
COPY --from=build /app/target/file.war /usr/local/tomcat/webapps 

In dit voorbeeld wordt één fase, build, gebruikt om de werkelijke Java-build uit te voeren met behulp van Maven. De tweede fase, beginnend bij 'FROM tomcat', kopieert bestanden vanuit de build fase. De uiteindelijke afbeelding is slechts de laatste fase die wordt gecreëerd, die kan worden overschreven met behulp van de parameter --target.

React-voorbeeld

Bij het bouwen van React-toepassingen hebt u een Node-omgeving nodig om de JavaScript-code, Sass-opmaakmodellen en meer te compileren in statische HTML, JavaScript en CSS. Als u geen rendering aan de serverzijde uitvoert, hebt u zelfs geen Node-omgeving nodig voor de productie-build.

FROM node:lts-alpine AS build
WORKDIR /app
COPY package* yarn.lock ./
RUN yarn install
COPY public ./public
COPY src ./src
RUN yarn run build

FROM nginx:alpine
COPY --from=build /app/build /usr/share/nginx/html

In dit voorbeeld wordt een node:lts-alpine image gebruikt om de build uit te voeren, waarmee de laag-caching wordt gemaximaliseerd en vervolgens de output wordt gekopieerd naar een nginx-container.

Hulpmiddelen opschonen

Bewaar alles wat u tot nu toe hebt gedaan om deze reeks zelfstudies voort te zetten.

Volgende stappen

U hebt geleerd over opties voor het behouden van gegevens voor container-apps.

Wat wilt u nu doen?