# Lab 10: Docker and docker compose ## *Kseniya Evdokimova* --- ## Questions to answer: ### Lab #### Installing Docker `sudo apt install docker docker.io` ![](https://i.imgur.com/tTiw5Il.png) `After installing, check on the status of the docker systemctl service by running` ![](https://i.imgur.com/TsLx8kG.png) It is already active, so we don't need to start it. I run the command `sudo usermod -aG docker $USER` and `newgrp docker` so Docker can be used by a non-root user. This means I won’t have to type sudo docker all the time. Instead of `$USER` I will write `kseniya`, since this is the current user (which was shown by `whoami`) ![](https://i.imgur.com/KVlLLUs.png) #### Creating your first Docker container To verify that things are installed correctly, I run `docker run hello-world` ![](https://i.imgur.com/azhN55N.png) It proves, that everything was installed successfully. #### Running an interactive container To install stuff on a bare Linux-like system without messing up the current system the following command can be used: `docker run -it ubuntu:xenial /bin/bash` It will run the Xenial version of Ubuntu in a container. ![](https://i.imgur.com/3e5YjBI.png) - -i flag tells docker to keep STDIN open to your container - -t flag allocates a pseudo-TTY for you Basically you need both for you to have a way to enter text and have this display properly. - /bin/bash is just the command you want to run once the container starts up We can exit the container with CTRL+D. To run Fedora, another long-running Linux distribution: `docker run -it fedora:latest /bin/bash` ![](https://i.imgur.com/YCZTVnQ.png) ### **Questions** ### 1. What user are you logged in as by default? We can find out the logged-in user by default by running `whoami` or by `id`: ![](https://i.imgur.com/cuA0uyU.png) It will be 'root'. The default user in docker exec is the same user used to start the container which can be set in docker run or your compose file. If the userwas not specified when starting the container, it will default to the user configured in the image (the image to look this up). This is configured by the last USER line in the Dockerfile. It may also be configured by a parent image specified by the FROM line. If neither the image, nor the run command specifies a user, docker defaults to root, uid 0. ### 2. If you start and then exit an interactive container, and then use the docker run -it ubuntu:xenial /bin/bash command again, is it the same container? How can you tell? No, docker will use same image, but after exiting and starting again the new interactive container will be created. We can confirm that by looking at the container's id after "root@". To verify this in more profound way, we can run: `sudo docker ps -aq` That will list all of the created containers. We can also see there first two produced by the same command - `docker run -it ubuntu:xenial /bin/bash` ![](https://i.imgur.com/LFggvbA.png) ### Lab #### Basic Management The Docker CLI (Command Line Interface) has some basic commands for you to monitor running and stopped containers, downloaded images, and other information. - Firstly, you might want to see the running containers on a system. Use the following command: `docker ps` Since no containers running, nothing will be displayed. However, passing in the -a flag, the stopped containers also will be visible (it displays weirdly, because of the wirth of the terminal): ![](https://i.imgur.com/6qKS0Yp.png) - To get more information about a container, we can use the docker logs command to fetch the logs of a container (whether it’s still running or exited): `docker logs <container_id_or_name>` ![](https://i.imgur.com/2NUr6TH.png) This basically just gives you stdout and stderr for process(es) running in the container. - To cleanup containers that have exited and you don’t plan on using anymore: `docker rm <container_id_or_name>` will remove the container. ![](https://i.imgur.com/d0tXrUK.png) - When running the Ubuntu or Fedora containers the first time that Docker downloaded a good chunk of data before running the image. This is the image of the container. We can view all of the images you’ve downloaded with the docker images command: `docker images` ![](https://i.imgur.com/4Scc3RA.png) - Images can take up quite a bit of space on your machine, so you may want to clean up images that you don’t plan on using. This is especially relevant if you get errors about not having enough disk space on your machine: `docker rmi <image_id>` The image files, as well as various filesystems of containers, are stored in /var/lib/docker. ### Dockerfiles An example of the Dockerfile that will build an image that has python3.6 installed. It will also run python3.6 directly, so we’ll be at a python prompt instead of a bash prompt when we run it. We will create the file "Dockerfile" using `nano` ![](https://i.imgur.com/UgfFJ7R.png) And put the following into this file: `FROM ubuntu:bionic RUN apt-get update && apt-get install -y python3.6 --no-install-recommends CMD ["/usr/bin/python3.6", "-i"]` There we specify a base image ubuntu:*bionic* (release 18.04 of ubuntu). We then specify that we should run (*RUN*) the command *apt-get update* and then *apt-get install python3.6* so we can install python3.6. Then we set the default command (*CMD*) of the container to run the python3.6 interpreter in interactive mode. ![](https://i.imgur.com/HxlGMTn.png) Then use Docker to build it with the following command: `docker build -t mypython:latest .` ![](https://i.imgur.com/cQnTDVn.png) ... ![](https://i.imgur.com/Q1WpvwR.png) This tells Docker to look in the current directory for a Dockerfile *to build*, and build it. The *-t* flag tells it to tag this build with the name *mypython:latest*. Docker will look for a Dockerfile in the current directory since we specified *by dot*. We can see all of the images we’ve built on the machine with the `docker images` command: ![](https://i.imgur.com/QXVRc9t.png) We also see here the *mypython* image ### **Questions** ### 1. Run the image you just built. Since we specified the default CMD, you can just do docker run -it mypython:latest. What do you observe? This container with default CMD will execute this command during the start of the container, if no any command passed as an argument. ![](https://i.imgur.com/WYCUYiC.png) By using `docker ps -a` we can confirm that after we will exit the container, it will stop: ![](https://i.imgur.com/tt3ypIn.png) ### 2. Write and build a Dockerfile by deploing python or any other application (e.g. web server and you can find it in github as example). Submit your Dockerfile with this lab? Let's start with making the directory 'python-docker' in which we will store the dockerfile and the image: `mkdir python-docker ` ![](https://i.imgur.com/nwjaM9N.png) Then we will install pip3. And by using it, we will install Flask: `sudo apt install python3-pip` ![](https://i.imgur.com/i9JhPwZ.png) `pip3 install Flask ` ![](https://i.imgur.com/ymIb2Zo.png) Let's create the file *requirements.txt* with specification of requirements for Flask: `touch requirements.txt` `pip3 freeze | grep Flask >> requirements.txt ` ![](https://i.imgur.com/C2L5Ou9.png) Finally, create the Flask app: `nano app.py` ![](https://i.imgur.com/Ut3gA26.png) It will open a webpage with the phrase about the Backman's books: ![](https://i.imgur.com/15zPyDB.png) Now, we will establish the updated Dockerfile: `nano Dockerfile` ![](https://i.imgur.com/l9HAeXQ.png) ### **Dockerfile** ![](https://i.imgur.com/2RcxXKU.png) - *#syntax=docker/dockerfile:1* - specifies for Docker the syntax which should be used for parsing the Dockerfile. - *FROM python:3.8-slim-buster* - specifies the inherited image containing all the tools and packages we need to run an application. - *WORKDIR /app* - tells the Docker to use this path as the default location for all following commands. - *COPY requirements.txt requirements.txt* - just copies our file - *RUN pip3 install -r requirements.txt* - for installing the dependencies of the image - *COPY . .* - copies all files from current host directory to the work directory on Docker - *CMD [ "python3", "-m" , "flask", "run", "--host=0.0.0.0"]* - commands that we run when our image is executed inside a container For building an image we will run: `docker build -t python-flask .` ![](https://i.imgur.com/PZtY7B3.png) For running the container we will run: `docker run python-flask` ![](https://i.imgur.com/JgxVY84.png) By searching `http://172.17.02:5000` we will see: ![](https://i.imgur.com/BQTfcgX.png) **Node.js application** To run a node.js application from the provided link, we need to update a Dockerfile. When container is created it will execute the command node server.js and will start to listen to port 8080: ![](https://i.imgur.com/XeLKPEh.png) Building image: ![](https://i.imgur.com/CnjMlnU.png) Running container: ![](https://i.imgur.com/PamAFzE.png) ### 3. Paste the output of your docker images command after questions 1 and 2. ![](https://i.imgur.com/fJ12vy7.png)