Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions 01-basics/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Makefile for the 'basic' example

include ../include/make/init.mk

start: ## Start the example
@printf "\n\033[1;33m%s\033[0m\n\n" "Starting the example..."
@docker compose up

cleanup: ## Cleanup any stopped containers
@printf "\n\033[1;33m%s\033[0m\n\n" "Cleaning up stopped containers..."
@docker compose down
5 changes: 5 additions & 0 deletions 01-basics/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# 01 Basic

1. Run `make start` or `docker compose up`.
2. See the Docker "Hello World" message printed to the console.
3. Run `make cleanup` or `docker compose down`.
4 changes: 3 additions & 1 deletion 01-basics/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
## This is a basic Docker Compose file

## Version of the Docker Compose file
## Version of the Compose specification you're using in this file (optional)
version: '3.7'

## Service definitions
services:
## Service name
hello-world:
## Image to use
image: hello-world
15 changes: 15 additions & 0 deletions 02-service-config/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Makefile for the 'service-config' example

include ../include/make/init.mk

start: ## Start services
@printf "\n\033[1;33m%s\033[0m\n\n" "Starting services..."
@docker compose up -d

restart: ## Restart Docker services
@printf "\n\033[1;33m%s\033[0m\n\n" "Restarting services..."
@docker compose restart

stop: ## Stop services
@printf "\n\033[1;33m%s\033[0m\n\n" "Stopping services..."
@docker compose down
9 changes: 9 additions & 0 deletions 02-service-config/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# 02 Service Configuration

1. Run `make start` or `docker compose up -d`.
2. Go to [http://localhost:4000](http://localhost:4000) in your web browser.
3. See the "Hello world!" message printed in your browser.
4. Run `make stop` or `docker compose down`.

- You shouldn't be able to get to [http://localhost:3000](http://localhost:3000) in your web browser.
- Even though our Node.js server is listening on port 3000, our Docker service publishes to port 4000 on the host.
28 changes: 28 additions & 0 deletions 02-service-config/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
## This is a Compose file with a service configuration

services:
node:
## Image to use, with a specific tag
image: node:20

## User to run the container as
## This is a user that exists in the image
user: node

## Volumes to mount to the container
## The first path is the host path, the second is the container path
## The dot (.) represents the current directory
volumes:
- .:/home/node/app

## Set the working directory inside the container
working_dir: /home/node/app

## Publish ports from the container to the host
## This lets you access the service from your own machine, e.g. through a browser
## The first port is the host port, the second is the container port
ports:
- 4000:3000

## Command to run when the container starts
command: npm start
7 changes: 7 additions & 0 deletions 02-service-config/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"private": true,
"name": "example-service-config",
"scripts": {
"start": "node server.js"
}
}
14 changes: 14 additions & 0 deletions 02-service-config/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const { createServer } = require('node:http');

const hostname = '0.0.0.0';
const port = 3000;

const server = createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World!');
});

server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
15 changes: 15 additions & 0 deletions 03-networking/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Makefile for the 'networking' example

include ../include/make/init.mk

start: ## Start services
@printf "\n\033[1;33m%s\033[0m\n\n" "Starting services..."
@docker compose up -d

restart: ## Restart Docker services
@printf "\n\033[1;33m%s\033[0m\n\n" "Restarting services..."
@docker compose restart

stop: ## Stop services
@printf "\n\033[1;33m%s\033[0m\n\n" "Stopping services..."
@docker compose down
12 changes: 12 additions & 0 deletions 03-networking/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# 03 Networking

1. Run `make start` or `docker compose up -d`.
2. Go to [http://localhost:4000](http://localhost:4000) in your web browser.
3. See the backend's message printed in your browser.
4. Run `make stop` or `docker compose down`.

- You shouldn't be able to get to [http://localhost:3000](http://localhost:3000) in your web browser.
- Even though our Node.js server is listening on port 3000, our Docker service publishes to port 4000 on the host.
- You shouldn't be able to get to [http://localhost:5000](http://localhost:5000) either.
- Our backend service doesn't publish **any** ports to the host - but it does expose it to the frontend service.
- This means the frontend service can talk to our backend, but no one else can.
7 changes: 7 additions & 0 deletions 03-networking/backend/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"private": true,
"name": "example-networking-backend",
"scripts": {
"start": "node server.js"
}
}
14 changes: 14 additions & 0 deletions 03-networking/backend/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const { createServer } = require('node:http');

const hostname = '0.0.0.0';
const port = 5000;

const server = createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('This is a message from the backend!');
});

server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
43 changes: 43 additions & 0 deletions 03-networking/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
## This is a Compose file with multiple services and networking

services:
frontend:
image: node:20
user: node
volumes:
- ./frontend:/home/node/app
working_dir: /home/node/app
ports:
- 4000:3000
command: npm start

## Attach the frontend service to our network
networks:
- my-network

## Let's add another service for our backend
backend:
image: node:20
user: node
volumes:
- ./backend:/home/node/app
working_dir: /home/node/app
command: npm start

## Expose the port to the frontend service
## This is different from `ports`, which publishes ports to the host
## Instead, `expose` makes the port available to other services in the same network - but not to the host
expose:
- 5000

## Attach the backend service to our network
networks:
- my-network

## Define the networks for our services
networks:
## Create a network called my-network
my-network:
## Use the bridge driver
## This creates a private internal network that only our services can access
driver: bridge
7 changes: 7 additions & 0 deletions 03-networking/frontend/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"private": true,
"name": "example-networking-frontend",
"scripts": {
"start": "node server.js"
}
}
32 changes: 32 additions & 0 deletions 03-networking/frontend/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
const { createServer } = require('node:http');
const http = require('http');

const hostname = '0.0.0.0';
const port = 3000;

const server = createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');

const backendUrl = 'http://backend:5000';

http.get(backendUrl, (backendRes) => {
let data = '';
backendRes.on('data', (chunk) => {
data += chunk;
});
backendRes.on('end', () => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end(data);
});
}).on('error', (err) => {
console.error(`Error accessing backend: ${err}`);
res.statusCode = 500;
res.end('Internal Server Error');
});
});

server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
20 changes: 20 additions & 0 deletions 04-volumes/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Makefile for the 'volumes' example

include ../include/make/init.mk

start: ## Start services
@printf "\n\033[1;33m%s\033[0m\n\n" "Starting services..."
@docker compose up -d

restart: ## Restart Docker services
@printf "\n\033[1;33m%s\033[0m\n\n" "Restarting services..."
@docker compose restart

stop: ## Stop services
@printf "\n\033[1;33m%s\033[0m\n\n" "Stopping services..."
@docker compose down

inspect-volume: ## Inspect the backend-logs named volume
@printf "\n\033[1;33m%s\033[0m\n\n" "Inspecting the backend-logs named volume..."
@docker volume inspect 04-volumes_backend-logs
@printf "\n\033[1;35m%s\033[0m\n\n" "💡 You can view the contents of the volume by opening the mountpoint in your file explorer."
14 changes: 14 additions & 0 deletions 04-volumes/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# 04 Volumes

## Running the application

1. Run `make start` or `docker compose up -d`.
2. Go to [http://localhost:4000](http://localhost:4000) in your web browser.
3. See the backend's message (number of requests) printed in your browser.
4. Run `make stop` or `docker compose down`.

## Viewing the files in the named volume

1. Start the services.
2. Run `make inspect-volume` or `docker volume inspect 04-volumes_backend-logs`.
3. Open the `mountpoint` path in your file explorer program.
7 changes: 7 additions & 0 deletions 04-volumes/backend/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"private": true,
"name": "example-volumes-backend",
"scripts": {
"start": "node server.js"
}
}
54 changes: 54 additions & 0 deletions 04-volumes/backend/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
const { createServer } = require('node:http');
const fs = require('fs');
const readline = require('readline');

const hostname = '0.0.0.0';
const port = 5000;

const server = createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');

const logFilePath = '/home/node/app/logs/access.log';

const clientIP = req.socket.remoteAddress;
const timestamp = new Date().toISOString();

fs.access(logFilePath, fs.constants.F_OK, (err) => {
if (err) {
if (err.code === 'ENOENT') {
fs.writeFile(logFilePath, '', (err) => {
if (err) {
console.error('Error creating access log file:', err);
}
});
} else {
console.error('Error checking access log file:', err);
}
}
});

fs.appendFile(logFilePath, `[${timestamp}] Connection from ${clientIP}\n`, (err) => {
if (err) {
console.error('Error writing to access log:', err);
}
});

const lineReader = readline.createInterface({
input: fs.createReadStream(logFilePath),
});

let lineCount = 0;

lineReader.on('line', () => {
lineCount++;
});

lineReader.on('close', () => {
res.end('The backend server has received ' + lineCount + ' requests.');
});
});

server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
45 changes: 45 additions & 0 deletions 04-volumes/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
## This is a Compose file with a named volume

services:
frontend:
image: node:20
user: node
volumes:
- ./frontend:/home/node/app
working_dir: /home/node/app
ports:
- 4000:3000
command: npm start
networks:
- my-network

backend:
image: node:20
user: node
volumes:
## Note that we're mounting the backend folder to /home/node/app/src
## This is so we can separate the source code from the logs
- ./backend:/home/node/app/src

## Add a named volume for the backend logs
## This will store the logs in a volume that can be shared between containers
- backend-logs:/home/node/app/logs

working_dir: /home/node/app/src
command: npm start
expose:
- 5000
networks:
- my-network

networks:
my-network:
driver: bridge

## Define our volumes
volumes:
## Create a named volume called backend-logs
backend-logs:
## Use the local driver
## This stores the volume on the host machine in a folder managed by Docker
driver: local
7 changes: 7 additions & 0 deletions 04-volumes/frontend/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"private": true,
"name": "example-volumes-frontend",
"scripts": {
"start": "node server.js"
}
}
Loading