The natural hair community, a group of people, who all embrace and love their hair whether that be straight, wavy, curly, kinky. For a long time, most people who identify with the curly and kinky…
Docker 101
A Docker image is a private filesystem, just for your container. It provides all the files and code your container will need. Running the docker build command creates a Docker image using the Dockerfile. This built image is in your machine’s local Docker image registry.
Great! Now let’s run your first container.
Running a container launches your software with private resources, securely isolated from the rest of your machine.
Once you’re ready to share your container with the world, push the image that describes it to Docker Hub.
Images are single files containing all the dependencies and configurations required to run a program, while containers are the instances of those images. Let’s go ahead and see an example of that in practice to make things clearer.
Let’s say you don’t have Python installed in your machine — or at least not the latest version — and you need python to print “Hello, World!” in your terminal. What do you do? You use docker!
Go ahead and run the following command:
Don’t worry, I’ll explain that command in a second, but right now you are probably seeing something like this:
That means we are currently inside a docker container created from a python 3 docker image, running the python
command. To finish off the example, type print("Hello, World!")
and watch as the magic happens.
Alright, you did it, but before you start patting yourself on the back, let’s take a step back and understand how that worked.
Let’s start from the beginning. The docker run
command is docker's standard tool to help you start and run your containers.
The --rm
flag is there to tell the Docker Daemon to clean up the container and remove the file system after the container exits. This helps you save disk space after running short-lived containers like this one, that we only started to print "Hello, World!".
The -t (or --tty)
flag tells Docker to allocate a virtual terminal session within the container. This is commonly used with the -i (or --interactive)
option, which keeps STDIN open even if running in detached mode (more about that later).
Last but not least, python
was the command we told Docker to execute inside our python:3
image, which started a python shell and allowed our print("Hello, World!")
call to work.
To exit python and terminate our container, you can use CTRL/CMD + D or exit()
. Go ahead and do that right now. After that, try to execute our docker run
command again and you'll see something a little bit different, and a lot faster.
That’s because we already downloaded the python:3
image, so our container starts a lot faster now.
What’s better than writing “Hello, World!” in your terminal once? You got it, writing it twice!
Since we cannot wait to see “Hello, World!” printed in our terminal again, and we don’t want to go through the hustle of opening up python and typing print
again, let's go ahead and automate that process a little bit. Start by creating a hello.py
file anywhere you'd like.
Next, go ahead and run the following command from that same folder.
This is the result we are looking for:
As we did earlier, let’s take a step back and understand how that worked.
We are pretty much running the same command we ran in the last section, apart from two things.
The -v $(pwd):/src
option tells the Docker Daemon to start up a volume in our container. Volumes are the best way to persist data in Docker. In this example, we are telling Docker that we want the current directory - retrieved from $(pwd)
- to be added to our container in the folder /src
.
If you want to check that /src/hello.py
actually exists inside our container, you can change the end of our command from python hello.py
to bash
. This will open an interactive shell inside our container, and you can use it just like you would expect.
The last bit of our command is the python /src/hello.py
instruction. By running it, we are telling our container to look inside its /src
folder and execute the hello.py
file using python
.
Maybe you can already see the wonders you can do with this power, but I’ll highlight it for you anyway. Using what we just learned, we can pretty much run any code from any language inside any computer without having to install any dependencies at the host machine — except for Docker, of course. That’s a lot of bold text for one sentence, so make sure you read that twice!
Are you tired of saying hello to our beautiful planet, yet? That’s a shame, cause we are gonna do it again!
The last command we learned was a little bit verbose, and I can already see myself getting tired of typing all of that code every time I wanna say “Hello, World!” Let’s automate things a little bit further now. Create a file named Dockerfile
and add the following content to it:
Now run this command in the same folder you created the Dockerfile
:
All that’s left to do now is to go crazy using this code:
You already know how it is. Let’s take a moment to understand how a Dockerfile works now.
Starting with our Dockerfile, the first line FROM python:3
is telling Docker to start everything with the base image we are already familiar with, python:3
.
The third line, COPY . .
is basically telling Docker to copy everything from our current folder (first .
), and paste it on /src/app
(second .
). The paste location was set with the WORKDIR
command right above it.
Finally, the last line CMD ["python", "./hello.py"]
is providing the default command for our container. It's essentially saying that every time we run
a container from this configuration, it should run python ./hello.py
. Keep in mind that we are implicitly running /src/app/hello.py
instead of only hello.py
, since that's what where we pointed our WORKDIR
to.
With our Dockerfile finished, we go ahead and start our build
process. The docker build -t hello .
command reads all the configuration we added to our Dockerfile and creates a docker image from it. That's right, just like the python:3
image we've been using for this entire article. The .
at the end tells Docker that we want to run a Dockerfile at our current location, and the -t hello
option gives this image the name hello
, so we can easily reference it at runtime.
After all of that, all we need to do is run the usual docker run
instruction, but this time with the hello
image name at the end of the line. That will start a container from the image we recently built and finally print the good ol' "Hello, World!" in our terminal.
Following our python example, if we needed the numpy
library to run our code, we could add the RUN
instruction right after our FROM
command.
The RUN
instruction basically gives a command to be executed by the container's terminal. That way, since our base image already comes with pip3
installed, we can use pip3 install numpy
.
I know you are probably tired of hearing me say it, but I have one more “Hello” to say before I go. Let’s go ahead and use our newly acquired docker power to create a simple long-lived container, instead of these short-lived ones we’ve been using so far.
Create an index.html
file in a new folder with the following content.
Now, let’s create a new Dockerfile in the same folder.
Lastly, let’s run our newly created image with the following command:
You might be thinking that nothing happened because you are back to your terminal, but let’s take a closer look with the docker ps
command.
Everything seems to be working as expected, and we are serving a static page through the nginx
running inside our container. Let's take a moment to understand how we accomplished that.
Apart from what is new, this configuration works because nginx
uses the usr/share/nginx/html
folder to search for an index.html
file and start serving it, so since we named our file index.html
and configured the WORKDIR
to be usr/share/nginx/html
, this setup will work right out of the box.
The build
command is exactly like the one we used in the last section as well, we are only using the Dockerfile configuration to build an image with a certain name.
The second new flag is the -p 8080:80
option. As you might have guessed, this is the port
flag, and it's basically mapping the port 8080
from our local machine to the port 80
inside our container. You could have used any other port instead of 8080
, but you cannot change the port 80
without adding an additional setting to the nginx
image, since 80
is the standard port the nginx
image exposes.
Blockchain is one of the hottest and most intriguing technologies on the market. Similar to the rise of the Internet, Blockchain is already touted by entrepreneurs, start-ups, investors and global…
We live in the era of the technological revolution, the software industry is at its best, thousands of startups are created annually and a large number of companies have their own development team…
In a climate where it feels like no two people, groups, or entities can reasonably get along, I believe I have uncovered a unanimous truth that may unite us all: bed bugs are the fucking worst. We…