Getting Started with Docker (Pluralsight Notes)

Notes from Pluralsight course "Getting Started with Docker" by Nigel Poulto

Notes from Pluralsight course "Getting Started with Docker" by Nigel Poulton

  • Hypervisors virtualize hardware. However, containers virtualize operating systems (with their own process trees, eth0, directory structure).
  • Because containers don’t virtualize the lower level hardware, all containers share the same kernel.
  • This makes containers smaller, faster, and more lightweight than standard VMs. This allows for way more "apps per square foot", or app density
  • You can test Docker Containers for free at labs.play-with-docker.com
  • An "image" is like a stopped VM while a "container" is like a running VM. Images are stored in the cloud or locally then become containers once you run them.
  • In the same way, an image is like a class, and a container is like an object instance created from that class

Dockerfile

  • Dockerfile states how to build the image
  • These use docker key words, but they are executing commands inside the container.
FROM node:current-alpine 
# this doesn't actually have a linux kernel. 
# Just file system constructs and Node installed 

LABEL org.opencontainers.image.title="Hello Docker Learners!" \
      org.opencontainers.image.description="Web server showing host that responded" \
      org.opencontainers.image.authors="@nigelpoulton"
# this you can ignore. Its just who you can hassle about the app

# Create directory in container image for app code
RUN mkdir -p /usr/src/app

# Copy app code (.) to /usr/src/app in container image
COPY . /usr/src/app

# Set working directory context
WORKDIR /usr/src/app

# Install dependencies from packages.json
RUN npm install

# Command for container to execute
ENTRYPOINT [ "node", "app.js" ]

Build the Image

  • Build with…
docker image build \
-t <docker_user_id>/<repo_name>:<image_or_version_name> \
.
  • Example:
docker image build \
-t jairusc615/first-container:v1 \
.
  • You can then see the image with docker images
  • You can then delete this image with docker image rm. Example:
docker image rm \
jairusc615/first-container:v1

Hosting Image

  • Hosting on a registry like DockerHub
  • There are loads of container registries out there
  • Login to DockerHub with
docker login
  • You may need to make an access token in DockerHug and use that as an alternative to your password.
  • Push to DockerHub with…
docker image push \
<docker_user_id>/<repo_name>:<image_or_version_name>
  • Example:
docker image push \
jairusc615/first-container:v1

Running a Containerized App

  • Run a docker container with…
docker container run -d \
--name <name> \
-p <external_port_num>:<container_port_num> \
<docker_user_id>/<repo_name>:<image_or_version_name>
  • Example:
docker container run -d --name web -p 8000:8080 jairusc615/first-container:v1
  • If docker can’t find the image locally, it will automatically search in DockerHub
  • -d means detached. It will run in the background, detached from the terminal. You could leave this off, and you automatically get a shell into the container! But then as soon as you exit, the container is killed. You can keep it running instead of exiting with Ctrl+P+Q to send it to the background.
  • See all running containers with docker container ls
  • See all containers (regardless of if theyre running or not) with docker container ls -a

Managing a Containerized App

  • Stop container with docker container stop <docker_container_name_or_id>
  • This sends a sigint to the app and allows 10 seconds for graceful shutdown. If it does not stop, it sends a sigkill.
  • Start container with docker container start <docker_container_name_or_id>
  • Delete a container be stopping it first, then use docker container rm <docker_container_name_or_id>
  • You can also delete without stopping the container by using the -f flag. Ex. docker container rm <docker_container_name_or_id>

Cloud-Native Microservices

  • A single app could have a frontend, database, logging, keychain, backend, api, and other services along with it. These all must go together for the app to work!
  • In other app infrastructures, these all come packaged together. So if you take one down to upgrade it or package it, its all down! That it big and clunky!
  • Instead, we split the app into separate micro-services that all work together but are in separate containers
  • You can then upgrade only one part of the app without touching the others.

Multi-Container Apps with Docker-Compose

  • The docker-compose.yaml is a declarative manifest file describing an app. Example:
version: "3.8"
services:
  web-fe: # type of service
    build: .
    command: python app.py # command the container will run to start the service
    ports:
      - target: 5000 # container port
        published: 5000 # host port
    networks:
      - counter-net
	  # notice we connect the two services on the same network
    volumes:
      - type: volume
        source: counter-vol # declared below
        target: /code # mount point
  redis: # type of service
    image: "redis:alpine"
    networks:
      counter-net:

networks: # declare this network for creation and bind it to this app
  counter-net:

volumes: # declare this volume for creation and bind it to this app
  counter-vol:
  • The requirements.txt file declared the dependencies needed. Example:
flask
redis
  • Create, start, or restart the app with docker-compose up and the optional aforementioned -d flag if desired (which is likely)
  • Stop the app with docker-compose down

Docker Swarm

  • Load balancing and redundancy capabilities!
  • A swarm is a cluster of one or more manager nodes and some worker nodes
  • Manages nodes control things like the cluster store, scheduling, etc. Usually have an odd number of these, like 3 or 5. This is to ensure that if managers are for some reason disconnected, they can know if they have the majority or not because its not an even tie. That even tie is called a "split brain"
  • You can run swarm mode on Docker Desktop, but you only get one manager node.
  • Swarm unlocks Docker Services, which map directly to application micro-services.
  • To create a swarm, have many instances running Docker. Then, on one of them, run docker swarm init. This will make this node the first manager node. You will probably need the flag --advertise-addr=<host_ip_address> so that that particular ip address is used for cluster communication.
  • To add a manager to the swarm, run docker swarm join-token manager and a command will pop up that you can then run on the new manager.
  • To add a worker to the swarm, its similar to adding a manager. Ex. docker swarm join-token worker
  • To see all the docker managers, run Docker node ls. Any node without Manager Status is a worker

Micro-Services and Docker Services

  • Every micro-service has an associated docker service that controls and scales it.
  • To create a docker service, run docker service create, with similar parameters to before. (docker service create is only available in swarm mode.) Example:
docker service create --name web -p 8080:8080 \
--replicas 3 \
<docker_user_id>/<repo_name>:<image_or_version_name>
  • See the service with docker service ls. This will only show you local containers.
  • The best command for seeing all containers is docker service ps <service_name_or_id> because it will show you all containers, even if they aren’t local.
  • You should edit a service with docker service, and probably not mess with docker container directly
  • If you delete a container directly, docker will automatically recreate it in the swarm. This simulates what would happen if a container failed.
  • Scale the service with docker service scale <service_name_or_id>=<integer> . Example: docker service scale web=10 will get you 10 instances of the web container, all load balanced.
  • Remove the service with docker service rm <service_name_or_id>

Multi-Container Apps with Docker Swarm

  • The docker-compose.yaml file looks similar to before… Example.
version: "3.8"
services:
  web-fe:
    image: nigelpoulton/gsd:swarm-stack
	  # ^this used to be "build: ."
    command: python app.py
    deploy: # <-----
      replicas: 10 # <-----
    ports:
      - target: 8080
        published: 5000
    networks:
      - counter-net
    volumes:
      - type: volume
        source: counter-vol
        target: /code
  redis:
    image: "redis:alpine"
    networks:
      counter-net:

networks:
  counter-net:

volumes:
  counter-vol:
  • Stacks can’t build images on the fly, so you can’t use the local dockerfile with build: .. The web front image needs to be pre-created and stored in a registry so that all the nodes can pull it. Reference it with image: <docker_user_id>/<repo_name>:<image_or_version_name> in the above file
  • That being said, use the dockerfile to build the image, then push it to a registry, and you’re good to go.
  • To run the stack from the docker-compose.yaml file, use…
docker stack deploy -c docker-compose.yaml <name_of_app_or_stack>
  • See all running stacks (or apps) with docker stack ls
  • See the services of a stack with docker stack services <stack_or_app_name>
  • The best way to change a stack on the fly is just to edit the docker-compose.yaml file and re-run the deploy to enforce the changes

Future Courses to Continue Learning

Share this post
Jairus Christensen

Jairus Christensen

Articles: 19

Leave a Reply

Your email address will not be published. Required fields are marked *