Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save arrested-developer/0e950b2b74b50e89b305cf6d9a7f28b5 to your computer and use it in GitHub Desktop.
Save arrested-developer/0e950b2b74b50e89b305cf6d9a7f28b5 to your computer and use it in GitHub Desktop.

Run a local HTTP server with Docker 🐳

Serve your static website from localhost using Docker and Nginx.

By @arrested-developer

Why Docker?

Do you know the famous phrase "it works on my machine"?

a dinosaur bragging that it works on his machine

Well, when you work in a team with people with other machines, and you test your software online on other machines, and you deploy it to a server on another machine, that might not be good enough...

With Docker there is no excuse anymore. Docker allows you to locally run the same (or almost the same) environment which will be used in production, and to be sure you're running the same environment as everyone else on your team.

So let’s get started understanding what Docker is and what Docker is not. This is going to be an interactive introduction - you'll be setting up and using containers yourself before we're done. Whenever we reach a ✅CHECKPOINT ✅, we'll be checking our own knowledge. If you need to do a little more reading or chat with your team to answer the questions, go for it.

What is Docker?

Docker is a computer program that performs operating-system-level virtualization, also known as “containerization”.

More than that, Docker is a popular tool to make it easier to build, deploy and run applications using containers. Containers allow us to package all the things that our application needs like such as libraries and other dependencies and ship it all as a single package. In this way, our application can be run on any machine and have the same behaviour.

Docker was first released in 2013, only 5 years ago, but it is already used by a lot of companies, like: Spotify, The New York Times, PayPal, Uber and more (https://www.contino.io/insights/whos-using-docker).

Last but not least, Docker is open source: https://github.com/docker. ❤️

Docker is not…

Docker is not a virtual machine (VM)

A Docker container, unlike a virtual machine, does not require or include a separate operating system. Instead, it relies on the kernel’s functionality and uses resource isolation for CPU and memory, and separate namespaces to isolate the application’s view of the operating system

a dog reacting with confusion

Let's unpack that a little...

Unlike a VM, which runs a whole virtual instance of a separate (often different) Operating System within a host machine, a Docker container takes a much more lightweight approach. By keeping its own resources separate from those of the host machine, it can run a machine that is to all intents and purposes independent and separate from the host, however it still uses the host kernel.

(From Wikipedia)

The kernel is a computer program that is the core of a computer's operating system, with complete control over everything in the system.[1] On most systems, it is one of the first programs loaded on start-up (after the bootloader). It handles the rest of start-up as well as input/output requests from software, translating them into data-processing instructions for the central processing unit. It handles memory and peripherals like keyboards, monitors, printers, and speakers.

✅CHECKPOINT ✅

  • How is Docker different from a Virtual Machine?
  • Why is this important?
  • Why use Containers?

Hands on tutorial

First up, let's install Docker

https://docs.docker.com/docker-for-mac/install/

Once you've got it installed, let's do a quick demo

Hello World

Jeff Goldblum waving hello

With Docker properly installed and running, let’s start creating containers.

The “Hello World” in Docker is simple like that:

$ docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
9db2ca6ccae0: Pull complete
Digest: sha256:4b8ff392a12ed9ea17784bd3c9a8b1fa3299cac44aca35a85c90c5e3c7afacdc
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.

As you can see, it shows the following message:

Unable to find image ‘hello-world:latest’ locally

It means you haven’t an image called “hello-world” locally so it will automatically pull from Docker hub.

Docker hub is basically:

A cloud-based registry service which allows you to link to code repositories, build your images and test them, stores manually pushed images, and links to Docker Cloud so you can deploy images to your hosts. It provides a centralized resource for container image discovery, distribution and change management, user and team collaboration, and workflow automation throughout the development pipeline.

After pulling the hello-world image, it will run the container and will show a Hello from Docker! message with some other information.

Congratulations, you have run a “Hello World” in Docker!

✅CHECKPOINT ✅

  • What happened when we ran hello world?
  • What is a Docker image?

Serving HTTP requests from your localhost

You may have already used VS Code's Live Server to do something similar to this.

What we want to do it set up a local HTTP server, which you can access from localhost (a way to describe your local computer's address). We can then use it to serve up HTML, CSS and JS files as if we were accessing them on the real live interweb.

a person surfing the internet

✅CHECKPOINT ✅

  • What is an HTTP server?
  • How is the HTTP protocol used to exchange information?
  • What are HTTP status codes and why are they important?

Running a local HTTP server

We're going to follow a quick tutorial to set up Nginx

(see https://hub.docker.com/_/nginx for more info)

Create a dockerfile in your project

In the folder where you have your last week's project, create a new file called Dockerfile

In that file, add the following:

FROM nginx
COPY ./public /usr/share/nginx/html

The first line is telling Docker to use the nginx image.

Further reading - What is a Docker image?

The second line is telling Docker to copy the files in the sub-folder public to the server's HTML folder ready to be served up. Let's move the files our project needs to run into a sub-folder called public, allowing us to keep any files not required for our app to run private.

Then, run the commands to build and run the Docker image:

$ docker build -t my-week-1-project .
$ docker run --name my-nginx-server -d -p 8080:80 my-week-1-project

Go to localhost:8080 to see your app

✅CHECKPOINT ✅

  • What is the command docker build doing?
  • What is the command docker run doing?
  • How might you change the port used on localhost?
  • What is port 80 typically used for?
  • How do you stop your container running? Docker command line docs
  • What happens if you execute the docker run command without the -d flag?

Next Steps

If you've got all this down, you may have noticed there is some limitation to what we've set up. We've got a HTTP server serving up our files as a fully functioning website (yay!) but what happens if you make changes to your HTML? Your CSS? 🤔

In our current setup, the files from ./public were copied to the server at build time. This is a one-time process, so unless you stop, remove and rebuild your container, you won't see any changes to the files.

Using a bind mount

In order to be able to refresh our browser and see our changes on the fly, we need to use what Docker calls a bind mount

  1. Lets stop our docker container with docker stop <your-container-name>
  2. Remove the current build of the container with docker rm <your-container-name>
  3. Edit the Dockerfile to remove the second line that copies in the files
  4. Rebuild your container
  5. When you run your container, use the -v flag to add a bind mount.

You'll need to supply two arguments - the first is the folder on your host machine that you want to make available in the container, the second is the location to put it in the container, e.g.

-v ~/my-files/project-1/public:/usr/share/nginx/html

Get your container running with a bind mount from your public folder to the container's html folder as above. Try changing your files and refreshing the page and see what happens!

Further reading - bind mounts

Adapted from:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment