<jupyter_start><jupyter_text>Your first image!Ok now that you understand what Docker is and why use it (at least I hope, if not you will soon!), it is time to get more technical. GoalIn this module we will learn:* What is the **concrete** difference between an **image** and a **container*** How to create an image?* What is a Dockerfile and how to use it?* How to create a container out of an image?And we will run our very first container based on our very first image!![do-it](./assets/do-it.gif)  InstallationFirst things first, we need to install Docker.You just have to follow [Docker's well made documentation](https://docs.docker.com/engine/install/ubuntu/).If you're running Windows or Mac -> https://docs.docker.com/engine/install/By default, Docker will need to use `sudo` each time. Let's change that:```bashsudo gpasswd -a $USER docker```You will need to log-out before it applies the changes. How do we create an imageIn order to create images (or import them), we could: Go to [Docker Hub](https://hub.docker.com/) which is like GitHub for Docker images. You need an image with a SQL DB in it? [There is one](https://hub.docker.com/r/mysalt/mysql). You need an image with python 3.6? [There is one](https://hub.docker.com/r/silverlogic/python3.6).And a lot of other images! Create your own docker file!In many cases, we will want to create our own images, with our own files and our own script.In order to do that we will create what we call a `Dockerfile`. This is just a file that is named `Dockerfile` and that contains a script that Docker can understand.Based on that, it will create an image. Let's create our imageIt's time! So we will create a `Dockerfile` and we will use a python image as base. It means that we start from an existing image to build our own.So we don't have to start from scratch each time.In this file we will add a line to tell Docker that we want to start from the official Python 3.7 image.The `FROM` keyword is used to tell Docker which base image we will use.```DockerfileFROM python:3.7```Now let's add another line to copy a file. In the folder you're in, there is a file named `hello_world.py`. This file contains a single line:```pythonprint("Hello world!")```We will create folder called `app` and put our file in it. As the python image is built on top of Ubuntu, we can use all the commands that work in Ubuntu.Let's see some useful keywords that can be used in a Dockerfile:* The `RUN` keyword can be uses to run a command on the system.* The `COPY` keyword can be used to copy a file.* The `WORKDIR` keyword can be used to define the path where all the commands will be run starting after it.* The `CMD` keyword can be used to define the command that the container will run when it will be launched.```DockerfileRUN mkdir /appRUN mkdir /app/codeCOPY code/hello_world.py /app/code/hello_world.pyWORKDIR /appCMD ["python", "code/hello_world.py"]``` Let's build our image!Now we're ready to create our first image! Exciting right? We say that we `build` our image. That's the term. The command is: `docker build . -t hello`* `docker` to specify that we use docker* `build` to specify that we want to create an image* `.` to specify that the Dockerfile is in the current directory* `-t hello` to add a name to our image. If we don't do that we will need to use the ID that docker defines for us and it's not easy to remember.I already created the Dockerfile for you. Have a look on it!<jupyter_code>!docker build . -t hello<jupyter_output>Sending build context to Docker daemon  1.938MB
Step 1/5 : FROM python:3.7
 ---> 2b00bba7acbb
Step 2/5 : RUN mkdir /app
 ---> Using cache
 ---> b37597b12c4e
Step 3/5 : COPY hello_world.py /app/hello_world.py
 ---> 5951097814ca
Step 4/5 : WORKDIR /app
 ---> Running in e0bf5f50ab1f
Removing intermediate container e0bf5f50ab1f
 ---> 3afec94712bc
Step 5/5 : CMD ["python", "hello_world.py"]
 ---> Running in 305147184ee0
Removing intermediate container 305147184ee0
 ---> 8f7ca704c0a8
Successfully built 8f7ca704c0a8
Successfully tagged hello:latest<jupyter_text>As you can see, our image has been successfully built!If you look at the last line of the output, you see:```Successfully tagged hello:latest```Our image has been tagged with `hello:latest`. As we didn't define any tag at the end of our image name, `latest` will be added by docker.If we make changes in our image and re-build it, a new image will be created with the tag `latest` and our old image will no longer have it. It's useful when you want to use the most recent version of your image.We can also add our own tags as follows<jupyter_code>!docker build . -t another_image:v1.0<jupyter_output>Sending build context to Docker daemon  1.942MB
Step 1/5 : FROM python:3.7
 ---> 2b00bba7acbb
Step 2/5 : RUN mkdir /app
 ---> Using cache
 ---> b37597b12c4e
Step 3/5 : COPY hello_world.py /app/hello_world.py
 ---> Using cache
 ---> 5951097814ca
Step 4/5 : WORKDIR /app
 ---> Using cache
 ---> 3afec94712bc
Step 5/5 : CMD ["python", "hello_world.py"]
 ---> Using cache
 ---> 8f7ca704c0a8
Successfully built 8f7ca704c0a8
Successfully tagged another_image:v1.0<jupyter_text>If we try to list all of our images, we will see that we have 3 images. * One `hello` with the tag `latest`* One `hello` with the tag `v1.0`* One `python` with the tag `3.7` *(that's the one we used as base image)*We can see it with:```bashdocker image ls```<jupyter_code>!docker image ls<jupyter_output>REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
another_image       v1.0                8f7ca704c0a8        15 minutes ago      876MB
hello               latest              8f7ca704c0a8        15 minutes ago      876MB
hello               v1.0                8f7ca704c0a8        15 minutes ago      876MB
python              3.7                 2b00bba7acbb        2 days ago          876MB<jupyter_text>Manage imagesAs you can see images take a lot of place on you hard drive! And the more complex your images are and the more dependencies they have, the bigger they will be.It rapidly become a pain...Thankfully, we can remove the one that we don't use anymore with the command:```bashdocker image rm ````As we see in the `docker image ls` output, each image has an ID. We will use that to remove them. Let's say we want to remove our `hello:v1.0` image.```hello               latest              8f7ca704c0a8        7 minutes ago       876MB```Here the ID is `8f7ca704c0a8`. But here multiple images have the same ID. That's because multiples images you the same image.Confused? It's because Docker is really smart! We tried to create multiple images based on the same Dockerfile, and there were no changes between the creation of the first image and the last one. Neither in the files, nor in the Dockerfile. So Docker knows that it doesn't have to create multiple images! It creates and 'links' it to other tags.So if I try to delete with the ID it will give me a warning and not do it. Because multiple tags are linked to the same image.So instead of using IDs we will use tags.<jupyter_code>!docker image rm hello:v1.0<jupyter_output>Untagged: hello:v1.0<jupyter_text>The tag has been removed!<jupyter_code>!docker image ls<jupyter_output>REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello               latest              8f7ca704c0a8        21 minutes ago      876MB
python              3.7                 2b00bba7acbb        2 days ago          876MB<jupyter_text>Run itPerfect! You understand what an image is now! Let's run it. When we will run the image, Docker will create a `container`, an instance of the image and it will execute the command we added after the `CMD` keyword.We will do it with the command:```bashdocker run -t hello:latest```* `run` is to tell to docker to create a container.* `-t hello:latest` is to specify which image it should use to create and run the `container`If you don't put `:` docker will add `:latest` by default.<jupyter_code>!docker run -t hello<jupyter_output>Hello world!<jupyter_text>Our container successfully ran. We can see that it printed 'Hello world' as asked.Ok. So we created a container and we ran it. Can we see it stored somewhere?Let's try with `docker container ls` maybe?<jupyter_code>!docker container ls<jupyter_output>CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES<jupyter_text>Damn it, the command seems to be right but there is nothing here!Well, `docker container ls` only show running containers. And this one is not running anymore because it completed the task we asked him to do!So if we want to see all the container, including the stopped one, we can do:```bashdocker container ls -a```<jupyter_code>!docker container ls -a<jupyter_output>CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                      PORTS               NAMES
cd585b842f8b        hello               "python hello_world.…"   55 minutes ago      Exited (0) 55 minutes ago                       confident_agnesi<jupyter_text>Ok good! We can of course remove it with:```bashdocker contaier rm ```So in this case `cd585b842f8b`<jupyter_code>!docker container rm cd585b842f8b<jupyter_output>cd585b842f8b
{'fraction_non_alphanumeric': 0.07218271924154276, 'fraction_numerical': 0.03145873734109028, 'mean_word_length': 3.2759097190234914, 'pattern_counts': {'":': 0, '<': 28, '<?xml version=': 0, '>': 46, 'https://': 5, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '9', 'dir': 'jupyter-structured-clean-dedup', 'id': '144450', 'license': 'MIT', 'n_tokens_mistral': 2912, 'n_tokens_neox': 2609, 'n_words': 1307, 'path': 'Bonus_resources/deployment/2.Docker/2.your_first_image.ipynb', 'repo_name': 'becodeorg/ai_fundamentals_1.0', 'size': '9282'}