📚 Literature Notes
Docker

Docker

What?

  • Virtualize the Application Layer (Layer 7)
    • create, deploy, run app in isolated containers, containers can be deployed on cloud infrastructure
  • Not a Cloud Computing Platform or Service docker is used to facilitate cloud computing
  • package software
    • 代码和所有依赖项打包到单个容器中来简化构建、部署和扩展应用程序的过程
  • Options
    • docker in docker
      • Docker Desktop Application
    • docker outside docker
      • docker extension in VSCode Dev Containers (container configuration)
  • Docker Desktop
    • uses a Virtual Machine Monitor(VMM)/Hypervisor Layer 虚拟机监控程序 with a lightweight Linux distro

What Concepts?

  • CORE
    • Dockerfile (builds image) .devcontainer/devcontainer.json (container configuration)
      • blueprint/code for building a docker image ⇒ run app as container
    • Docker Image (run containers) - immutable (read-only), layers, templates
      • Docker Registries (get images)
      • Docker Repository - collection of related Docker Images with same name but different versions
        • Docker Hub (opens in a new tab) is a Public Docker Registry, can host private/public repositories for app
          • a centralized resource for working with Docker and its components
          • [registry hostname]/repository[:tag] (e.g. [docker.io/]nginx:alpine or nginx[:latest])
          1. login docker login --username=xinyun2016
            1. docker login [OPTIONS][SERVER]docker login -u xinyun2016
          2. or login to a private Docker registry (e.g. AWS ECR, Nexus Server )
            1. docker login -u AWS https://ecr.ap-southeast-2.amazonaws.com
          3. logout docker logout [SERVER]docker logout
      • Image Tags (Image Versioning )
        • a label applied to a Docker Image in a Repository
        docker pull node:buster            ## node with tag buster
        docker pull node:8                 ## might be intel based image => but actually arm based
    • Docker Container (running process) - instance of image
      • 1 image ⇒ can run multiple containers
      • app inside container runs in Isolated Docker Network
        • allows run same app ⇒ on same port multiple times
      • need to expose the container port to the host (the machine the container runs on)
        • Port Binding - bind the container’s port to the host’s port to make the service available to the outside world
  • Docker Compose - multiple containers, single-host
    • docker-compose.yml (docker-compose.yaml) - multiple containers, dependency management
    • can use but don't have to have Dockerfile (builds image)
    • docker-compose start containers in docker-compose.yml
  • Docker Volumes (Persist data in Docker) - multiple containers
  • Docker SWARM mode - orchestration, multi-host
  • "bridge": containers share the same port, each with a different IP, and expose a host port, making them visible externally. (Docker Network Documentation (opens in a new tab))
  • Dev Containers (container configuration) ⇒ .devcontainer/devcontainer.json (container configuration)
    • uses one of
      • Dockerfile (builds image)
      • docker-compose.yml (docker-compose.yaml) - multiple containers, dependency ⇒ can use Dockerfile

What are Docker CLI? (Docker Commands)

  • Check image/container status

    • docker images list all Docker Images (run containers) - immutable (read-only), layers, templates
      • docker images [OPTIONS] [REPOSITORY[:TAG]] ⇒ list all images docker image ls or docker images
    • docker ps list running containers (container port, container id)
      • every container has a unique id ⇒ also linked to an image
      docker ps       # lists all containers (running)
      docker ps -a    # lists all containers (stoped and running)
       # -a or --all    lists all containers (stoped and running)
      sudo docker ps -a
  • Main process

    • docker pull - pull image (can skip as run also pull)

      docker pull NAME[:TAG]
      docker pull nginx
      docker pull nginx:1.23
      docker pull node:buster            ## node with tag buster
      docker pull node:8                 ## might be intel based image => but actually arm based
    • Run a Docker CONTAINER

      • Create & Start Container

        1. docker create [OPTIONS] IMAGE [COMMAND] [ARG…]docker create --name nginx -p 8080:80 nginx
        2. docker start [OPTIONS] CONTAINER [CONTAINER…]docker start nginx
      • docker run 🟢 Run & Pull Image ⇒ show log (create new container everything, don't re-use previous container)

        • Port Forwarding

          • --name container name

          • -e set an environment variable in the container

          • -p/--publish map host port => container port (expose the port )

            • -p {LOCAL_HOST_POST}:{CONTAINER_PORT}
              • LOCAL_HOST_POST: check in server.js
          • -d detached mode => run in background

            • runs in the bg & doesn't attach to the terminal)
            • if not have ⇒ quit terminal ⇒ container stops
          • --restart always

            • define restart policy => always (is container stop => restart)
          • e.g.

            • docker run --name nginx -p 8080:80 -d nginx
            docker run nginx                       ## docker run {name}:{tag} creates a container from image and starts it
            docker run --name web-app -d -p 9000:80 nginx:1.23    # expose container to local network localhost:9000
             
            ## this wont work b/c EXPOSE 8080 by default is not accessible to the outside world
            # docker run b909406d737c ## create a running process called a container => terminal will say app listening on localhost 8080
             
            ## Need refactor the command with p flag => implement port forwarding from the docker machine to our local machine
            docker run -p 5000:8080 b909406d737c ## map local machine 5000 => to a port on the docker container 8080
            ## app will run on localhost:5000
             
            docker ps     ## check the container port => list running containers
            docker ps -a  ## list all containers
            docker log {CONTAINER_ID/NAME}
          • other use case

            • Start a Container (Named Volume)
            • Start a Container (Bind Mount)
            • Create a container from the image
    • Modify existing Docker CONTAINER

      • docker stop 🛑 stop the container
        docker ps
        docker stop ea491e4t0fd7 # docker stop {CONTAINER_ID/NAME} stop one or more running containers
          # stop multiple with [space] in between the {CONTAINER_ID/NAME}
      • docker start 🟢 start the stopped container (running container ⇒ keep running)
        docker ps -a # show all stopped and running container
        docker start {CONTAINER_ID/NAME}
      • docker restart restart a container (running container ⇒ stop & restart)
      • docker rm ➖ remove a non-running container
        • docker rm -f nginx ➖ remove a running container
    • Create a Docker IMAGE

      • docker build 🟢 build docker image with Dockerfile (builds image) (run Docker) Dev Containers (container configuration)
        • ready repo ⇒ deploy to server ⇒ we want to deploy our app as a Docker Container
        • image ⇒ run ⇒ container
          • need Dockerfile (builds image)
        • Syntax docker build [OPTIONS] PATH
          • -t /--tag sets name:tag or userName/imageName:versionNumber
          • . path to the Dockerfile (builds image) (in this case .)
          1. Build New Image => with ./Dockerfile => with name "demo2"
            • docker build -t angular-app:1.0 .
            • docker build -t fireship/demoapp:1.0 . ## name and path to the docker file (in this case .)
            • docker build -t demo2.
          2. Create a container from the image
            • docker run -d -p 3000:3000 node-app:1.0
            • docker run --name demo2 -e WELCOME_STRING="COMP90024" -p 8081:80 -d demo2
    • docker-compose start containers in docker-compose.yml (docker-compose.yaml) - multiple containers, dependency

      1. Check no containers running
        • docker ps list running containers (container port, container id)
      2. Start the containers with docker-compose.yml (docker-compose.yaml) - multiple containers, dependency
        • docker compose up -d for docker v2
          • -d detached mode
          • -f filename
          • e.g.
            • docker compose -f compose.yaml up start all the containers in compose.yaml
            • docker-compose up -d for docker v1 (will be end of life)
      • docker compose stop 🛑 stop the containers
      • docker compose down ❌ remove the container
    • Pushing a Docker Image

      • (optional) tag an image docker tag <SOURCE_IMAGE> <TARGET_IMAGE>docker tag nginx xinyun2016/comp90024:nginx
      • push an image docker push <NAME[:TAG]>docker push xinyun2016/comp90024:nginx
  • 🐞 debugging

    • docker logs - see app log in the container

      docker ps               # show the container id
      docker logs ea491e4t0fd7 # docker logs {CONTAINER_ID/NAME} view logs from service running inside the container (chich are present at the time of execution)
    • docker exec -ti ⚠️ not recommended, mainly for debug or testing purpose

      docker exec -ti w /usr/share/nginx/html/ nginx sh
      sed -i 's/nginx!/nginx inDocker!/g' index.html    ## replace text
      • ./list-volume-mount.sh
    • docker volume - manage volume

      • ls - list all volumes

      • rm VOLUME_NAME - remove volume

      • Manage data in Docker

        1. Create a volume

          • docker volume create --name htdocs
            • have this volume we can mount it somewhere in our container when we run it
            • multiple containers can mount this volume simultaneously and access the same set of files
            • the file stick around after all containers shut down
        2. Start a Container (Named Volume)

          ## start a container "nginx-volume" with a VOLUME attached
          docker run --name nginx-volume -p 8080:80 -v htdocs:/usr/share/nginx/html -d nginx
          ## NAMED VOLUME
          ## docker run             Create & Start      new container
          ## --name nginx-volume    CONTAINER NAME      "nginx-volume"
          ## -p 8080:80             maps                hostPort 8080 => containerPort 80
          ##                        localhost:8080      running inside the container
          ## -v htdocs:/usr/share/nginx/html
          ##                        DOCKER VOLUME       "htdocs" volume's file accessible by web server inside the container
          ##                        mounts to container "/usr/share/nginx/html" web server's document root
          ## -d nginx               DOCKER IMAGE        "nginx" DOCKER IMAGE
          ##                        -d run container in detached mode (in background) wont output any logs or information to the console
          ## last line is the id of container
        3. Start a Container (Bind Mount)

          ## start a container "nginx-bind" with BIND MOUNT attached
          docker run --name nginx-bind -p 8081:80 -v $(pwd)/htdocs:/usr/share/nginx/html -d nginx
          ## BIND MOUNT
          ## docker run             Create & Start      new container
          ## --name nginx-bind      CONTAINER NAME      "nginx-bind"
          ## -p 8081:80             maps                hostPort 8081 => containerPort 80
          ##                        localhost:8081      running inside the container
          ## -v $(pwd)/htdocs:/usr/share/nginx/html
          ##                        mounts local "htdocs"  => container dir "/usr/share/ngine/html"
          ##                        local dir accessiable by web server inside container
          ## -d nginx               DOCKER IMAGE        "nginx" DOCKER IMAGE
          ##                        -d run container in detached mode (in background) wont output any logs or information to the console
        4. ./list-volume-mount.sh

           
          ./list-volume-mount.sh
          docker exec -ti nginx-volume sh -c "ls -ltr /usr/share/nginx/html"
          docker exec -ti nginx-bind sh -c "ls -ltr /usr/share/nginx/html"
          ## docker exec             run cmd in the running container
          ## -ti nginx-volume        run cmd in interactive mode with a TTY shell => container "nginx-volume"
          ## sh                      starts a new shell session
          ## -c "ls -ltr /usr/share/nginx/html"
          ##                         cmd to run inside the shell session
          ## -ltr                    long format + sorted by modification time + reverse order
           
          ## named volumn => have content of the container (index.html)
          ## bind mount   => directory was empty
          ## named volume => contents can be populated by a container
          ## bind mount   => simply mount it
          cp index.html htdocs/      ## copy to BIND MOUNT
  • docker network

    ## create docker network
    docker network create mongo-network
     
    ## start mongodb
    docker run -d \
    --name mongodb \                          # container name
    -p 27017:27017 \                          # port
    -e MONGO_INITDB_ROOT_USEANAME=admin \     # environment variables
    -e MONGO_INITDB_ROOT_PASSWORD=password \
    -net mongo-network \
    mongo                                     # image
     
    ## start mongo-express
    docker run -d \
    --name mongo-express \
    -p 8080:8080 \
    -e ME_CONFIG_MONGODB_ADMINUSERNAME=admin \
    -e ME_CONFIG_MONGODB_ADMINPASSWORD=password \
    -e ME_CONFIG_MONGODB_SERVER=mongodb \
    -net mongo-network \
    mongo-express

Why?

Why do I use it?

  • Reproducible Environment
  • Quickly launch multiple instances of an application and load balance between them.
  • more than just a virtual env, isolated environment for all dependencies, multiple services, easy deployment, same environment for collaborators, python version, etc…

How?

How to install?

How to Dockerize Existing Repo in GitHub With Dev Container?

  • .devcontainer/devcontainer.json (container configuration)
  1. Create a Dockerfile (builds image)
    • docker run - Run & Pull Image ⇒ show log (create new container everything, don't re-use previous container)
  2. Build Docker Image (run containers) - immutable (read-only), layers, templates
    • docker build - build docker image with Dockerfile (run Docker) Dev Containers (container configuration)
  3. Run Docker Container (running process) - instance of image
    1. Run a Docker CONTAINER
  • With Existing NextJS

    1. existing NexJS project

    2. create Dockerfile

      # use official node runtime as parent image
      FROM node:14
       
      # set working dir to /app
      WORKDIR /app
       
      # copy current directory contents into container at /app
      COPY . /app
       
      # install dependencies
      RUN npm install
       
      # Build the nextjs project
      RUN npm run install
       
      # Expose the port that app will run one
      EXPOSE 3000
       
      # start the app
      CMD ["npm", "start"]
       
    3. build the docker image

      1. docker build -t my-nextjs-app this create a docker image named “my-nextjs-app”
    4. Run the Docker container

      1. docker run -p 3000:3000 my-nextjs-app this start the container and map port 3000 on the host to port 3000 in the container
    5. app now running in the docker container and accessible at http://localhost:3000

How to ignore node_modules?

  • .dockerignore

How to debugging? ⇒ use docker app

How to clear all images, containers, and volumes in Docker?

# remove containers, images, volumes
docker rm -f $(docker ps -aq)
docker rmi -f $(docker images -aq)
docker volume rm $(docker volume ls -q)

How to Check the Architecture of Docker Image?

docker pull node:buster            ## node with tag buster
docker pull node:8                 ## might be intel based image => but actually arm based
ls
cat /etc/os-release
  • docker image inspect node:buster | grep Arch
    • Intel -“Architecture”: “amd64"
      • Docker run will warn
        • WARNING: The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested
    • Apple Silicon -“Architecture”: “arm64"
  • In docker, desktop ⇒ container will show a AMD 64 tag need to the image name
  • Docker Desktop => Setting => Settings => Resources => Disk Image location /Users/alicezhang/Library/Containers/com.docker.docker/Data/vms/0/data