Diferencia entre revisiones de «Containers»

De Wiki de Sistemas Operativos
Saltar a: navegación, buscar
(Página creada con «In this practice we will learn how to use [https://es.wikipedia.org/wiki/Docker_(software) docker] to deploy containers. = Step 1: Installing docker = Let's add a new rep...»)
(Sin diferencias)

Revisión del 17:50 7 ene 2022

In this practice we will learn how to use docker to deploy containers.

Step 1: Installing docker

Let's add a new repository, since docker is not in the repositories official repositories:

sudo apt update
sudo apt install docker.io

To see if everything is OK and it has been installed correctly, we will check that the service is active:

sudo service docker status

It should display something similar to the following:

● docker.service - Docker Application Container Engine.
   Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
   Active: active (running) since Mon 2019-08-26 09:41:40 UTC; 37s ago
     Docs: https://docs.docker.com
 Main PID: 3630 (dockerd)
    Tasks: 8
   CGroup: /system.slice/docker.service
           └─3630 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

Press the 'q' key to exit.

If the service appears inactive, you can launch it with:

sudo service docker start

Step 2: Launch docker with our user

To avoid needing sudo when using docker, we will add our user to the group docker:

sudo usermod -aG docker ubuntu

For the change to take effect, we will need to log out of our user's user and open it again. We can easily do this by pressing CTRL + D and re-inserting our credentials.


= Step 3: DockerHub container image repository

Docker offers a cloud service called DockerHub that can be employed as a social network to share your Docker images. In DockerHub there are also preconfigured container images of software, many of them official (offered by the software manufacturer itself) that can be used as a basis for building new images tailored to our needs.

We will be able to perform searches in this repository DockerHub you can use the following command:

docker search hello-world

To download the hello-world image we can use the pull command:

docker pull hello-world

We can also publish our own images, this requires user registration' in the DockerHub cloud, which is not' mandatory for the realization of this practice. To upload an image, you have to validate yourself as a user in the DockerHub cloud:

docker login

After entering your login and password, you can start publishing your own images.

docker push MY_IMAGE

Step 4: Check images on our machine

To see the images we have on our machine, we will use the command:

docker images

Initially, we don't have images in storage, we can download the official Ubuntu image:

docker pull ubuntu:latest

Now yes, the ubuntu image should appear.

Comment also that each image can have several tags, for example, the ubuntu image, when we have seen it in the list of images, came with the tag latest, which is the tag that is downloaded by default, but we can specify another, for example:

docker pull ubuntu:bionic

To bring us the version of the Ubuntu image bionic (18.04).

Now we will have two images with different label, which would be like the different versions of each image.


= Step 5: Launch a container

A container is nothing more than a docker image running, it would be similar to a a virtual machine, although much lighter.

To create a container, we will use an image, in this case, the image hello-world image. We do the following:

docker run hello-world

This will show us the following message if everything is correct:

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

When creating containers using the 'run' command, we have several options:

Step 5.1: Run a terminal on the container in interactive mode (-ti)

For this example we are going to use a different image, in this case we are going to use an ubuntu image.

We are going to launch a container and run a terminal in which we are going to run the program bash' which offers me a command interpreter:

docker run -ti ubuntu bash

The -t option indicates that a terminal is created in the container. And the -i option indicates that the container is run in interactive mode.

When accessing the ubuntu container, a hash is displayed at the shell prompt, which identifies the container instance (this value is similar to the one displayed by the docker container ls command).

To exit the container, type 'exit' or press 'CTRL + D'.

Step 5.2 Running in the background (-d)

docker run -d hello-world

It will show us the container id and run in the background, so the output we got before is now not shown. In order to see this output, we can use the logs command and the display id above:

docker logs 2ec1daae4676a4e84dc04fd91399c1dfe92119544ff12ee307991fe573d3db64

== Step 5.3: Adding environment variables to a container == Step 5.3.

We will use the above image, and we will add an environment variable called TEST containing the value 'test'. In addition, we will also run the terminal as before, to check with the echo command, that the environment variable is created correctly. environment variable is created correctly:

docker run -ti -e TEST=test ubuntu bash

Now, from the container we can check the value of the $TEST environment variable.

echo $TEST
test


Step 6: List running containers

We have been testing and running containers in the previous step, let's see where are these containers we have run, and then we will see some more options of the run command.

We have two options for viewing the containers:

docker container ls -a

or the short version:

docker ps -a

Both do the same thing, and should show us output similar to the following:

CONTAINER ID CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e2bde5f5500c ubuntu "bash" 6 minutes ago Exited (0) 2 seconds ago pensive_sammet
544ad27dbc3c ubuntu "bash" 7 minutes ago Exited (0) 7 minutes ago serene_elgamal

In the information we will see that the container has the status exited, that means that it is not running and has already finished. Let's do a test to see a container running:

docker run -d ubuntu sleep 30

With the sleep 30 command we wait 30 seconds until the command finishes, so during those 30 seconds, the container will be running, let's see it:

docker ps -a
CONTAINER ID IMAGE IMAGE COMMAND CREATED STATUS PORTS NAMES
eacceb27d52d ubuntu "sleep 30" 12 seconds ago Up 11 seconds sharp_pasteur

Let's see some more options of the run command.

Step 6.1: Give a name to the container (--name)

By default, docker will automatically create a name as we have seen in the outputs of the docker ps -a command. We can set the container name we want with the --name option:

docker run -d --name my_ubuntu ubuntu

Step 6.2: Remove container when finished (--rm)

Let's mix everything seen above:

  • Launch in the background (-d)
  • Run container for 30 seconds (sleep 30)
  • Give a name to the image (--name)
  • Delete container when finished (--rm)
docker run -d --rm --name bye-bye ubuntu sleep 30

Before and after the 30 seconds have passed, we can check that the container has disappeared.

docker ps -a

Step 7: Stopping and deleting containers

Containers we can stop or delete them, let's see how to do it. First of all, we nothing, we will delete all the containers that are finished, to do this:

docker container prune
docker ps -a

We've got everything clean to continue, now let's create a container, using a linux command that doesn't terminate, so that the container will keep running infinitely: </syntaxhighlight>. running the container infinitely:

docker run -d -ti --name my_container ubuntu bash
docker ps -a

Let's stop it (we can use the given name or id):

docker stop my_container
docker stop e4901956f108
docker ps -a

We'll see that it's finished, and now we're going to delete it, but only this container, not like previously we deleted all of them. The same as to stop it, we can use the name or the id.

docker container rm my_container
docker container rm my_container
docker ps -a

We will see that we no longer have the container and it is correctly removed.

Step 8: Connect to a container that is running in the background

Let's re-run a container that does not terminate:

docker run -d -ti --name to_attach ubuntu bash

Now, let's connect to this container that is running in the background. background:

docker attach to_attach

We will see the bash command running, to finish, we do a 'CTRL + C', and now, we will see what has happened to the container:

docker ps -a

We will see it stopped, because what we have done was to connect to the container and stop the command that was running, so now we've got the container finished.


Step 9: Execute another command in a container

Let's see again how to execute a command in a container that is already running. already running:

docker run -d -ti --name to_exec ubuntu bash

Now, let's run a command on that container. The exec command is similar to the run command, but to execute a command inside a container:

docker exec -ti to_exec ls

We are now inside the container created earlier:

ps -a

Here we will see in the list of running processes.

Now let's exit the container, by typing 'exit' or 'CTRL + D', and let's check the status of the container:

docker ps -a

Now we will see that the container is still running, not like in the previous step.

Step 10: Persistence in containers

We are going to see that containers do not keep the data by default, they only give us give us a service but the data is NOT persistent. Let's create a container that we are going to leave running:

docker run -d -ti --name to_expire ubuntu bash

Now, let's create a folder in the container and check that this folder exists:

docker exec to_expire mkdir test
docker exec to_expire ls

We'll see that the folder exists, but what happens if we delete the docker and recreate one?

docker container stop to_expire
docker container rm to_expire
docker run -d -ti --name to_expire ubuntu bash
docker exec to_expire ls

We can check that the folder created earlier, does not exist if the container terminates. If we would like to maintain a persistence of data, we have several options:


Step 10.1: Maintain the persistence by changing the base image

We repeat the previous steps, but before stopping the container, we are going to save the state of the container in the image:

docker run -d -ti --name to_save ubuntu bash
docker exec to_save mkdir test
docker commit to_save ubuntu
docker stop to_save

Now, let's stop the container and run a new one to test that the data has persisted:

docker run -d -ti --name to_save_v2 ubuntu:with_directory_test bash
docker exec to_save_v2 ls

This creates an ubuntu image with the label "con_directory_test".

Step 10.2: Maintain persistence by creating volumes

The other option to maintain data is to mount a volume by running the container. First we will create a folder that will act as a volume on our machine, which will be the one we will mount later. machine, which will be the one we then mount for docker:

mkdir /home/ubuntu/volume

Now we are going to mount the folder by running the container, we do it with the -v option, which has 3 fields separated by ':':

  1. The volume on our machine.
  2. Where the volume will be mounted inside the container
  3. Mounting options, e.g. rw (read and write) or ro (read only)
docker run --rm -ti -v /home/ubuntu/volume:/volume:rw ubuntu bash
mkdir /volume/test
touch /volume/test/file
exit

Once we exit the container, we can see that on our machine are. the data:

ls /home/ubuntu/volume/
ls /home/ubuntu/volume/test

The next time we run a container, if we mount that volume, the data will be there. data will be there, plus this way has the benefit of sharing data between our machine and the our machine and the container in a simple way.


Step 11: Create our own docker image

To create a container image with a Python hug application, we first create the folder that will contain the files that allow us to create the image.

mkdir miapp
cd miapp

We define a Dockerfile file to define the image:

FROM python:alpine

ENV USERNAME="username"
RUN mkdir /app
RUN pip install hug
COPY endpoint.py /app
WORKDIR /app
CMD hug -f endpoint.py

Alternatively, you can create a Dockerfile using Ubuntu image as a base instead of Alpine.

And add the file endpoint.py which uses the Python hug framework with the following content:

import hug

@hug.get('/welcome')
def welcome(username="unknown"):
    """ Say welcome to username """
    return "Welcome " + username

This file is an example of using Python hug. If we make a request to /welcome?username="LSO", this will return the message "Welcome LSO".

Once we have the two files created in our virtual machine, we can build our image:

docker build -t app:v1 -f Dockerfile .

Let's explain what each line is for:

  • FROM: will serve to base on an existing image, in this case, a python alpine image, which contains python and does not take up much space.
  • ENV: to create environment variables
  • RUN: to execute commands, either to create a folder, install dependencies or any other option we need.
  • COPY: to copy data from our machine to the image
  • WORKDIR: to change the working directory.
  • CMD: this command will be executed by default when starting a container from this image.

This will build a docker image based on python:alpine, in which we have saved our small application, and it will saved our small application and it will run when we run a container based on that image. container based on that image. To check that the image has been created correctly, we list the images, and we should get an image with the name 'app' and tag name 'app' and tag 'v1':

docker images

Now let's create a container for our image, and we'll add a new option, -p 8001:8000. This option will cause the container's internal port 8000 to be exposed on port 8001 on our machine:

docker run --name my-app --rm -d -p 8001:8000 app:v1

Now let's test that our image and code works. On our machine we will do:

curl -X GET http://localhost:8001/welcome?username=LSO

We will check that the output of the curl command, is "Welcome LSO".

Before we finish, let's check another little detail that we added in our image, the environment variable USERNAME, let's check that it works:

docker exec -ti my-app ash
echo $USERNAME

It works correctly, but when running the container, we can change this environment variable as we saw in one of the previous steps:

docker run --rm -ti -e USERNAME=me app:v1 ash
echo $USERNAME

This will help us to have default options and the user can change it at will. change it at will, such as passwords or other details.