- [Instructor] Docker is almost universally used
to run network services such as web and database servers.
To make this easier, Docker offers a wide variety
of networking options to connect containers together
and to connect containers to the Internet.
For connecting them together, it offers private networks
where you can put each container on a network
and they can talk to each other,
but still be isolated from the rest of the containers
running on your computer.
For getting data into and out of the system as a whole,
Docker offers the option of exposing a port
or publishing a port.
That makes that port accessible
from outside the machine on which Docker is being hosted.
Through the combination of these,
you can wire up your networks pretty much any way you want.
To expose a specific port, you specify
the internal port that the program is listening on
and what port it should be listening on the outside
as well as, if you'd like, what protocol to use
and there are many more options.
We're going to cover the fundamentals here.
Let's head on over to the terminal and give this a try.
Okay, over here in my terminal, let's set up a
interesting but minimal example to show the flow
between several containers.
So, over here, on the left, we're going to start up a server.
The server's going to accept data from one client
and pass it to another.
Well and good, little more interesting than just one way.
And then we're going to have two clients on the right.
So, to start up the server here,
we've got this moderately long Docker command.
Let's break that down.
We start off with docker run, our usual,
then dash, dash, RM and TI for terminal interactive,
as we're prone to do.
Here's the interesting part:
we're going to say dash, P for publish.
And we're going to publish port 45678
and connect it to port 45678.
So we're just exposing the same port
on the inside of the container as on the outside.
It makes things easy to keep track of.
But to make things a little more interesting,
we're going to publish a second port: 45679.
And again, we'll keep it the same
on the outside and the inside.
I'm going to go ahead and use
the dash, dash, name parameter here
to give my Docker container an explicit name
instead of just letting Docker choose
an interesting but random one.
I'm calling it echo server.
The echo is kind of line wrapped there.
All right, and our usual example, Ubuntu 14.04,
and we'll run a shell.
Okay, now that I've got this container,
let's start up a bare minimum server.
The Netcat utility is a great network debugging program
for just moving bits from one place to another.
It's super simple and a good way to show off networking
without having to get concerned with anything else
like starting a web server.
So I'm going to run NC for Netcat,
dash, LP for listen on port, 45678.
But I want to take the output of that
and, instead of just writing to the terminal here,
use the pipe character to send it off to another program.
That other program is going to be another copy
of the Netcat program.
NC, dash, LP, that other port we specified: 45679.
So that means that data will get passed
into our system on one port
and then spit out on another port.
Let's go ahead and connect some clients to that.
Now, over here on my desktop, I've got Netcat installed,
but if you don't have Netcat installed, don't worry.
Docker can solve that too.
We'll get to that in just a sec.
So I'm going to go Netcat to local host
to the place where Docker is exposing that port
on port 45678
and connect to my other client.
NC, local host, port 45679.
And let's send some data.
All right, so in this case, the data went
from this computer to a port exposed on this computer.
Got passed into the container in one port,
passed between two programs within that container,
then passed back out to a port running on the host computer.
Now I mentioned that, if you don't have Netcat locally,
then Docker can solve that problem.
And that's a good example to illustrate
one of the differences between using Docker
directly on Linux, Docker on a Mac, and Docker on Windows.
So let's go over this little difference here
just to illustrate that point.
So I'm going to go ahead and clear each of these terminals.
Okay, so I've left the Docker server running here.
We're not going to touch it.
In fact, I'm just going to go up here
and start it listening again.
It only listens once per connection.
Okay, now over here, instead of running Netcat locally
just on the computer, I'm going to run
docker run and I'm going to choose an image that has Netcat.
Same one we used for the server, I know it has it.
Dash, dash, RM, dash, TI, Ubuntu, four, bash.
Okay, but who do we connect to?
Local host in this container refers to itself.
We want to refer to the host computer.
Now, if you're running Docker desktop on a Mac,
this is one of the cases where it's different.
Containers are not allowed to directly address
the container by IP address, at least not reliably,
so they've added a special host name
for containers to refer to the machine that is hosting them.
This special name is host.docker.internal.
And then I can put NC, host.docker.internal,
port 45678, and start that here.
Now I'm going to copy.
Paste and change the port number to the second one: 45679.
Oops, I forgot to actually start the container.
Docker run, dash, dash, RN, dash, TI,
Ubuntu 14.04, bash.
Okay, now I'm going to paste it and change the port number.
Here we go again.
All right, so that solved the problem of not having Netcat.
There's one more difference.
If you're doing this on Windows
and don't have Netcat locally,
well, you can always install it, it's a very useful program,
but Docker can solve that.
So the difference is that, if you're doing this on Windows,
you do exactly the same, everything,
except instead of saying host.docker.internal,
just put the IP address of your Windows machine.
Just put in the machine's host
or, if it has a DNS name, use that.
You don't need to use the special name host.docker.internal
on Docker desktop for Windows.
Now explicitly setting the internal
and external port numbers is very reliable.
You'll always know where to find your service.
But what if you want to run 12?
Turns out Docker has that solved.
You can leave off the host side of the port definition
and Docker will fill it in from one of the available ports.
This allows many containers running the same programs
to share a same host.
This is often used with some sort of an orchestration
or discovery service like Kubernetes or something like that.
Let's give that a try.
Here I am back at the terminal
and I'm going to bring up that last command we used
to run our echo server,
but this time, I'm just going to go ahead
and remove one of the sides, so here I'm specifying
only the port as seen from inside the container.
I'm going to let Docker choose the port on the outside.
Okay, it's running.
NC, dash, LP, exactly the same command.
45678, pipe, LP, 45679.
But what port did it choose?
Well, let's go docker port,
echo server.
That's why we gave it a name in that last example
so that we could look it up by name right here.
Says ah, port 45678 just happened to get assigned
to the available port: 32777.
And 32776 for the other one.
So I'll go ahead and say Netcat, local host,
and I'm going to enter the dynamically generated
external port: 32777.
Start up that side.
Oh, I have to hit Enter over here.
There we go, 32777, and then NC, local host,
32776 for 45679.
Yep, that's right, 32776.
All right.
Yes, it goes.
Now, in addition to working with TCP
as we did in our previous examples,
I just want to show briefly that Docker works just fine
with UDP and other protocols as well.
For publishing the ports, you specify the internal port
and the external port just like before,
but if you put a /protocol at the end, UDP or TCP,
then it will use those,
so let's take a brief example at that.
Okay, so here we are, we're going to run
a slightly simpler version of this program
just to make it quick.
I'll take out that second port
and, instead of specifying the internal and external,
I'm just going to put the internal port and /udp.
Say, let's do the same thing,
but in a less reliable network protocol.
Okay, start it at running,
but since it chose the port dynamically,
I need to go and look up which port it chose,
so let me do that again just like we did before:
docker port, echo server.
Ah, and this time, I see that it
dynamically chose port 32771.
So let me start something listening here.
NC, dash, U for UDP, listen port, 45678.
Hit Enter and, over here, let's connect to that one.
NC, dash, U for UDP, local host,
and again, if you're running it on Windows
and using a separate machine,
you would put your machine's actual IP address there
instead of local host,
just as we did in the previous example.
And then I'm going to put the dynamically assigned
port of 32771.
Hello world.
And over here, we see that Docker works
with both TCP and UDP.