# 🇬🇧 Little survival Docker guide for web developers that do not understand anything to Docker
First of all, a BIG THANK YOU to Alessio Coltellacci (opens new window), because he knew how to understand my questions and to explain things to me simply.
This blog post isn't a complete guide about Docker, but only some recipes I use for my own needs.
# First image and first container
# Use case
What do we want? I need a kind of virtualization of an Ubuntu machine with NodeJS installed
So, create a directories structure like that:
.
├── 00-dev-setup
│ ├── Dockerfile
│ └── workspace
│ ├── index.js
│ └── package.json
# Prepare the Dockerfile
Create a Dockerfile
file inside /00-dev-setup
Dockerfile
:
FROM ubuntu:latest
LABEL maintainer="@k33g_org"
RUN apt-get update && \
apt-get install -y apt-utils && \
apt-get install -y curl && \
apt-get install -y nano && \
apt-get install -y gnupg2 && \
curl -sL https://deb.nodesource.com/setup_11.x | bash && \
apt-get install -y nodejs && \
apt-get clean
WORKDIR /workspace
# Prepare the NodeJS application
Create the index.js
file inside /00-dev-setup/workspace
index.js
:
const express = require("express");
const bodyParser = require("body-parser");
const generate = require('project-name-generator');
let port = process.env.PORT || 9090;
let app = express();
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({extended: false}))
let machineName = generate({ words: 3, number: true }).dashed
app.disable('etag');
app.get('/', (req, res) => {
res.send(`
<!doctype html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<h1>👋 Hello 🌍, I am ${machineName}</h1>
</body>
</html>
`)
})
app.listen(port)
console.log(`🌍 ${machineName} is started - listening on`, port)
Create the package.json
file inside /00-dev-setup/workspace
package.json
:
{
"name": "hello-world",
"version": "1.0.0",
"description": "",
"scripts": {
"start": "node index.js"
},
"main": "index.js",
"dependencies": {
"body-parser": "^1.17.2",
"express": "^4.15.3",
"project-name-generator": "^2.1.3"
}
}
# Build the image
With these commands, I'll create a Docker image named
dev-console
cd 00-dev-setup
docker build -t dev-console .
... wait a little moment
# Create and Run the container
cd 00-dev-setup
docker run -v $(pwd)/workspace:/workspace -p 8080:9090 --name dev-container -i -t dev-console
What did we do?
- We created a container named
dev-container
from the image nameddev-console
- We are going to open a shell inside the running container,
-i -t
options - We can access to our http server on the
8080
http port (when our server listening on9090
inside the container) - We told the container that it can access to
workspace
directory on the host file system with this option:-v $(pwd)/workspace:/workspace
(that means you can update files from the container or and from the host)
all the options for
docker run
are here: https://docs.docker.com/engine/reference/commandline/run/ (opens new window)
Right now, you should get a prompt like that:
root@81efd35c7c10:/workspace#
If you type a ls
command, you should obtain:
index.js package.json
# Start your http server
Inside the shell of the running container, type:
npm install
and then,
npm start
You should obtain:
🌍 half-spiky-visitor-1390 is started - listening on 9090
note the generated name of the server:
half-spiky-visitor-1390
Now, from the host, you can access your website with http://localhost:8080 (opens new window)
Important remark:
- I can create another container from the same image to run another http server,
- but I will need to use another "external" http port:
docker run -v $(pwd)/workspace:/workspace -p 8081:9090 --name dev-container-other -i -t dev-console
- here I used the
8081
port and my new container is nameddev-container-other
,- so, I will be able to access to the new http server with this adress http://localhost:8081 (opens new window)
to exit frm the container:
Ctrl-c
(it stops the nodejs http server)exit
(you return to the shell of the host, and the container is stopped)
⚠️ Remark/Question: I thought that I needed to expose the HTTP port 8080, it looks like it works even without that (to be validated again)
# Some useful commands
- return to the shell of the running container:
docker start dev-container
thendocker attach dev-container
- stop a running container:
docker stop dev-container
- remove a container:
docker rm dev-container
(you can recreate it with thedocker run
command)
# 2 containers and 2 http servers
# Use case
What do we want?
- create 2 web servers from the same image (so, 2 containers)
- access to these 2 websites with "fancy" domain names
For that we are going to use the "internal network" of Docker and Nginx 🙀.
# First, build 2 containers to serve http servers
It's simple:
docker network create my-web
then, type:
docker run -v $(pwd)/workspace:/workspace -p 8081:9090 --net my-web --name dev-container-one -i -t dev-console
then, in another host terminal, type:
docker run -v $(pwd)/workspace:/workspace -p 8082:9090 --net my-web --name dev-container-two -i -t dev-console
Start the http server (npm start
) in the 2 container shells.
You can check that you can reach http://localhost:8081 (opens new window) and http://localhost:8082 (opens new window)
# Add a reverse proxy (Nginx)
In another directory, create a new Dockerfile
:
FROM nginx
RUN rm /etc/nginx/conf.d/default.conf
COPY default.conf /etc/nginx/conf.d
In the same directory create a default.conf
file:
server {
listen 80;
server_name hello-one.test;
location / {
proxy_pass http://dev-container-one:9090;
}
}
server {
listen 80;
server_name hello-two.test;
location / {
proxy_pass http://dev-container-two:9090;
}
}
Build your new nginx image:
docker build -t nginx .
Create your new nginx container:
docker run -d --net my-web --name nginx-container -p 80:80 -p 443:443 nginx
this container is in a "detached mode" (
-d
option), so you don't get a new shell, and stay in the shell of the host.
In your etc/hosts
file update this line:
127.0.0.1 localhost
like that:
127.0.0.1 localhost hello-one.test hello-two.test
And now, it's magic 🎩✨ you can reach your 2 web sites with http://hello-one.test and http://hello-two.test. 😀
Remark: if you want to add another website to Nginx, you need to rebuild the image and the container (there is probably a better solution)
# Magic way: use jwilder/nginx-proxy
There is a simpler way, using the nginx-proxy project: https://github.com/jwilder/nginx-proxy (opens new window)
First, remove all your containers (docker rm container_name
), then type this command:
docker run -d -p 80:80 -v /var/run/docker.sock:/tmp/docker.sock:ro jwilder/nginx-proxy
And now start 3 containers (each from the 00-dev-setup
directory, or fromthe directory where you setup your project). Start each container with the environment variable named VIRTUAL_HOST
that contains the domain name:
docker run -e VIRTUAL_HOST=yo-1.test -v $(pwd)/workspace:/workspace -p 8081:9090 --name dev-container-one -i -t dev-console
docker run -e VIRTUAL_HOST=yo-2.test -v $(pwd)/workspace:/workspace -p 8082:9090 --name dev-container-two -i -t dev-console
docker run -e VIRTUAL_HOST=yo-3.test -v $(pwd)/workspace:/workspace -p 8083:9090 --name dev-container-three -i -t dev-console
In each shell, run the npm start
command
In your etc/hosts
file update this line:
127.0.0.1 localhost
like that:
127.0.0.1 localhost yo-1.test yo-2.test yo-3.test
And now, you can access your containers with their 3 respective urls:
- http://yo-1.test (opens new window)
- http://yo-2.test (opens new window)
- http://yo-3.test (opens new window)
That's all for today. 🎄
Last Articles
- 🇫🇷 Type Result en Kotlin | 2020-10-31 | Kotlin
- 🇫🇷 Type Result en Kotlin | 2020-10-31 | Kotlin
- 🇬🇧 Every GitLab Page deserves a real CI/CD | 2020-07-23 | GitLab CI
- 🇫🇷 Lit-Element, commencer doucement | 2020-07-20 | WebComponent
- 🇬🇧 Build quickly and host easily your Docker images with GitLab and GitLab CI | 2020-06-02 | GitLab CI
- 🇬🇧 Deploy quickly on Clever Cloud with GitLab CI | 2020-05-31 | GitLab CI
- 🇫🇷 Borg Collective, mes jouets pour apprendre Knative | 2020-05-30 | Knative
- 🇬🇧 Borg Collective, Toys to learn Knative | 2020-05-30 | Knative
- 🇫🇷 M5Stack, une petit device IOT bien sympathique, programmable en Python | 2020-05-09 | IOT
- 🇫🇷 Knative, l'outil qui rend Kubernetes sympathique | 2020-05-02 | kubernetes