Hello, I’m Dalia. In this video I want to
give you a quick introduction to Docker and cover the most important concepts you
need to understand to start using Docker. I'll be using a java application for my examples but the same basic concepts apply for any
technology you're using for your applications. Let’s say you have an application written in Java
- a simple Hello World application for example. You run it and it prints Hello World as expected. In order for this application to run, your source code is compiled into class
files that are executed by the JVM. The JVM is in charge of interpreting
your application according to your operating system - and all of this
is sitting on top of your hardware. Now you have a co-worker who wants to run your
application. If the co-worker has a JVM already, you can just package your Hello World
application into a jar and send it over to them. Your co-worker can then take
this jar and run your application with a one-line command and
get your Hello World! Message. In this scenario, we may not
see the benefit of Docker. So, let’s explore a more realistic scenario. You have a web application and you’re using a
variety of technologies - maybe your application is using a database (for example, MySQL or
MongoDB) - maybe it’s using an application server (like Tomcat or Open Liberty)
- and this is all sitting on your JVM. You run your web application and
it works great on your machine. At this point, you want to share it with a
co-worker. So you package it up into a war and send it over to your
co-worker to run on their machine. In this case, your co-worker can’t simply run
one command and get your application up and running like our previous scenario. They have
to setup their database – maybe you even offer to help them with that but you find out they’re
using MacOS and you’re on Windows so you slowly withdraw your offer and tell
them they're on their own. They go off and spend a bunch of time
figuring out how to install the database. They get it setup and they’re
excited to get the app running. You tell them, oh yeah, you also have
to setup the application server too. They do that and finally
they have their full stack. Then, they go to run the application but then
they message you and tell you the app won’t start. Your first response is, “but
it works on my machine!”. You start debugging and you discover
that they’re using Java 8 and you used a new feature only available in Java 11.
You ask them to install Java 11 and use that to run your app. You keep doing this back and
forth until you finally get the app working…. ...and then someone on the testing team
asks you for your app so they can test it. ...and then someone from the deployment team
reaches out to you so they can deploy it or you want to deploy it in your CI/CD pipeline. And you have to go through that
setup pain over and over again. You think - there must be a better way! That’s when containers come in to help! What is a container? A container is a standard component
that allows you to package your application and its dependencies in
an easy-to-share way. Some of the most important characteristics of a container is that
they’re portable, isolated, and lightweight. The name “container” comes from shipping
containers. With shipping containers, you can ship a car or a bunch of apples and the ship
doesn’t need to worry about stacking the contents of a containers the right way, keeping them at the
right temperature or the contents interfering with one another. As long as you provide the contents
in a uniform container, they will be shipped. Similarly, your application can be a standalone
application, a web application an enterprise application, it could be written in Java, Kotlin,
Python, JavaScript, it could use databases, app servers or have whatever dependencies,
as long as you package it in a container, your co-worker, tester, or deployment person
can run your application with minimal work. Docker is the software platform
that allows you to do this. Let’s take a look at our application from
earlier and see how Docker can help us with our previous scenario through containerization. On my operating system, I’ll install Docker and
containerize my application and it’s dependencies. In my case, I’ll containerize my application
code, app server, along with the JVM. But I’ll separate out the database into a
separate container since it doesn’t need to be closely tied to my application. The
question is how does this setup benefit me? Well, instead of your co-worker having to
setup everything by hand and potentially make mistakes in the process, if they have
Docker installed, they can instead run a couple of docker commands that you provide
them and get my application up and running. This setup scales a lot better. A common question when
learning about containers is: What is the difference between
containers and virtual machines? They’re both trying to solve the same
problem but they approach it differently. Let’s take a look at the VM scenario. If we wanted
to run our applications in virtual machines, our setup would look like this. We’d have
our hardware which will be running a host operating system. Then we’ll have a hypervisor
which creates and runs our virtual machines. When VMs are created, each VM includes
its own guest operating system which the application runs on. Unfortunately, having a
guest operating system is not cheap resource wise – with each guest operating system,
lots of memory and CPU are taken up. Now, let’s compare that to Docker. As we’ve
seen before, Docker sits on our operating system layer. But with Docker containers, you
do not have a guest operating system, making docker containers much smaller
and faster than virtual machines. When we run our application in containers,
we use fewer resources than if we ran them in virtual machines which allows us to run more
containers if we’d like. The startup time on a container is also faster especially that it
doesn’t have a guest operating system to load. There are pros and cons to using containers vs
virtual machines. We won’t dive into that here but the main takeaway is that they both solve the “it works on my machine” problem but
approach the solution in different ways. Now that we’ve covered the
basics and benefits of docker, we’re ready to containerize our first application. In order to understand the process, we’ll take
the simplest application and containerize it. The first step is to install
Docker on your operating system. Second step is to build a docker image. A docker
image is what will be used to create your running container. It’s basically a template which is used
to create and run a container. In order to create an image, you need a Dockerfile which will include
the instructions on how to build a docker image. Third step is to run our docker
container from the docker image. If you’re not sure about the difference
between an image and a container, a helpful analogy are classes and runtime
objects in object-oriented programming. You can think of an image as a class -
and the container as the runtime object you instantiate from your class. You take a
Docker image and instantiate as many containers as you like. So a container is the
running instance of your image. Let's go ahead and see these steps in action. I’ll create a simple application. You
can use your favorite IDE to do so. I’ll create a new Java project, for my Java
version, I'll choose Java 11 - you can use whatever verison you'd like. I’ll select the
template option so I don’t have to type out the main method. I’ll name my project
- HelloWorldDocker. Then click Finish. In my main method, I'll print a “Hello World!”
string. Then, I'll go ahead and run it. Here is the current stack for
our Hello World application. I want to take this application
and run it in a Docker container. First, I need to install Docker. You can
install Docker from the get docker website, I’ve included the link in the description. Choose the instructions that go with
your operating system. I’m running on Windows – so I’ve already gone through the
Docker installation process for windows. Once docker is installed and has started,
I like to run the docker version command from my commandline to ensure that everything was
installed successfully and that docker is running. I’ll open up the terminal
window and run docker version. Now that I have Docker installed, I'm
ready for our second step which is to build a docker image. In order to create
an image, I need a Dockerfile. Let’s create that by
right-clicking on the project, clicking New -> file then entering Dockerfile.
Make sure you spell Dockerfile as seen here. This file will include our instructions on how to
build the image for our hello world application. The order of the commands in a Dockerfile is very
important as each line is executed one by one. An image is made out of layers. The first
instruction of a Dockerfile specifies the base layer of your image using the FROM
keyword then the name of the base image. With Docker, you get access to a public repository
for Docker images called DockerHub. You can browse DockerHub to see all the images available to
you. I've personally found that Docker makes it a lot easier to quickly setup a database
- I've used the mysql image lots of times. An important note here is to be careful
when you're pulling images from DockerHub. I only pull official images or
images from trusted sources. Now back to my application. Since I'm using Java,
I'll use the OpenJDK official image as my base image. Then, I will specify a colon then a tag, in
my case, I'll use the 11 tag which is the tag for Java 11. I could also leave the colon and tag
off which will pull the latest openjdk image. In your Dockerfile, you can add comments
in your Dockerfile with the hash sign. Next, I will create a new app
directory for my application files. I will use the RUN keyword followed by
the mkdir command with the directory name. Your Dockerfile can have multiple Run commands.
An important note here is that when you’re using the RUN command, you’re executing commands
for your image. Meaning that this line is creating a directory that will live inside
your container – not on your host machine. Next, I need to copy the application files
from my host machine into the image filesystem. So, I will use the COPY keyword then specify what
I'm copying from my host machine - in this case, it's my Main class file located in
the out directory - then the second argument is the directory in the
image where the files will be copied. I want to pause here and talk about the difference
between the COPY and RUN keywords. I used to get confused on when my instructions apply to the
image I'm creating and when they apply to my host machine. What helped me was to remember that when
I use RUN , the commands only apply to the image. But when I use COPY, the first argument applies to my host machine but the
second argument applies to the image. Next, I need to set the directory where I’ll
be executing future commands. I can do so with the WORKDIR keyword then
specifying the app directory. Lastly, every Dockerfile needs to specify
the command that will execute when you start a container from the image. Your
Dockerfile must contain one CMD or ENRTYPOINT instruction specifying the default
instruction for your container. In my case, I want to run my Main class when my container
starts. I'll use the CMD keyword then specify the command I would run if I was trying to run my
Main class from the terminal, which is java Main. And that’s all we’ll have in our Dockerfile.
The file basically says: pull an OpenJDK image, copy my application files into the image and
run the application when the container starts. There are other keywords you can use in a
Dockerfile but these are a good starting point. Now that we’ve finished writing our
Dockerfile, we’re ready to build our image. You can use this icon in IntelliJ IDEA to
build your image or you can use the terminal. Let's see how we can do this using terminal. We'll run the "docker build" command. Then,
I'll use the -t option to specify my image name and tag. I’ll call my image hello-world
and give it a 1.0 tag. You could also not have a tag and it’ll default to a tag called
“latest”. Then, I need to specify the path where my Dockerfile is located. Since I’m already
in the directory where the Dockerfile is located, I can just specify a dot here for
current directory. Now let's run this. The command runs and you see the output here
including the result of each instruction in your Dockerfile. When the FROM openjdk:11 instruction
is executed, Docker will look for the image locally and if it doesn't find it, it'll pull it
from DockerHub. Since I don't have the openjdk image locally, this build is taking a bit of
time but the subsquent builds won't take as long. Then we see the rest of
the Dockerfile instructions ran successfully and our
hello-world:1.0 image is built. If we want to see the current images
we have, we can run docker images. You'll now see my new hello-world
image is now listed with the 1.0 tag. You also see the image ID, when it
was created and the size of the image. At this point, we haven’t
actually run any containers yet, we just created an image. I want to instantiate
my image and run my container based on this image. We can do that with the "docker run"
command. I need to specify the name of the image that the container will be based on. I execute the docker run command
which creates the Docker container and runs it which prints
off a Hello World! message. This time, the Hello World! message is coming from
our application running in a Docker container. If we want to see the list of currently
running containers, we can run docker ps. You’ll notice that our container isn’t listed
here because our application prints hello world and immediately terminates.
Since the docker ps command only list the containers running right now,
we don't see our hello-world container. If we want to see a list of all containers,
running and stopped, we can run docker ps –a. Now, we see our container that already ran and
terminated. The Docker ps command lists all the container's information including the container
ID and the image this container was based on. You'll also notice that since we
didn't specify a container name, Docker gave it a random silly name. Let’s change our application code a bit to mimic
the behavior of a continuously running container. I’m going to add a loop that prints a message
every 2 seconds. You can imagine that this is some web application that you'll
have up and running for your users. I have made my source code changes but those
are not the files going in my image. When my image is built, Docker copies the class files so
I need to trigger an update to my class files. I'll do that by rebuilding my project.
Or you can simply run your application. The class files have been updated so I can build
a new image using the same build command from earlier - but this time, I'll give my image a
2.0 tag. The command runs and you'll notice it takes less time since we already have the
openjdk:11 image pulled from last time. Now let’s run a new container from my 2.0 image.
This time, I’m going to run the container in detached mode using the -d option which means that
the container will start and run in the background without taking up my console window with all
the messages being printed every 2 seconds. The command is executed which
starts a container in the background and prints out the new container's ID. Now, this time, if I run docker ps, we see the container in our list
since it's currently running. From, here I can start as many
containers as I would like. Let’s start another container from my 2.0
image. We can use the same command again. Now I see two containers when I run docker ps. If I want to see what is
happening in my containers so far, I can use the docker logs command and pass in the
ID of the container I want to see the logs of. Notice that I can use the short version of the
ID printed in the docker ps command instead of the very long one that was printed
after my container was first created. Looks like my container is
currently on iteration 22. If you're using IntelliJ IDEA, you can also see a list of images and
containers in the services windows. There are lots of Docker features available in
IntelliJ IDEA that make developing application in Docker easier. You can learn about
them through the link in the description. This wraps up our video. I hope
it was beneficial and you can now get started using Docker with your
applications. Thanks for watching!