Compare commits
10 Commits
3f0d1d77ca
...
master
Author | SHA1 | Date | |
---|---|---|---|
36356093ff | |||
03e9317041 | |||
b6c684cdd1 | |||
8e2cd7f9a1 | |||
fa25dde20f | |||
1696808c00 | |||
7aa80d9800 | |||
761ea8fef8 | |||
94a71d6d77 | |||
66fc64dcac |
18
examples/devcontainers/.devcontainer/devcontainer.json
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"name": "Fullstack DevContainer",
|
||||||
|
"dockerComposeFile": ["../compose.yml", "../compose.override.yml"],
|
||||||
|
"service": "backend",
|
||||||
|
"workspaceFolder": "/app",
|
||||||
|
"shutdownAction": "stopCompose",
|
||||||
|
"forwardPorts": [80, 8080],
|
||||||
|
"postCreateCommand": "/entrypoint.sh",
|
||||||
|
"customizations": {
|
||||||
|
"vscode": {
|
||||||
|
"extensions": [
|
||||||
|
"jripouteau.adonis-vscode-extension",
|
||||||
|
"dbaeumer.vscode-eslint",
|
||||||
|
"esbenp.prettier-vscode"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
49
examples/devcontainers/README.md
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
# Overview
|
||||||
|
This is a practical example of a "basic" fullstack application. This application has been fully containerized to be run locally in development mode as well as for deployment to production. It is composed of the following services:
|
||||||
|
|
||||||
|
- frontend - Basic React app bootstrapped with `yarn create vite`
|
||||||
|
- backend - AdonisJS API Backend [https://adonisjs.com]()
|
||||||
|
- database - Postgres database
|
||||||
|
- reverse_proxy - Traefik ingress controller handling reverse proxy for the frontend and backend applications.
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
### Devcontainer
|
||||||
|
You can run this project via dev containers. First you will need to ensure that you have the [VSCode dev containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers)
|
||||||
|
|
||||||
|
Once you have the extension installed, there are a couple ways to get started. From this directory run `code .` to open a new VSCode window targeting this directory. After a few seconds you should get a notification in the bottom right asking if you want to reopen the workspace in a container. This will open a new VScode window and will start the process of building and running all of the containers.
|
||||||
|
<video src="./open-devcontainers-option1.m4v" controls></video>
|
||||||
|
|
||||||
|
Another method is to open the `Command Palette` (CMD+Shift+P) and search for `Dev Containers: Open Folder in Dev Container`. Select this folder and VScode will open a new window and kick off the process. The very first time you do this it will take several minutes to build the images and start the containers.
|
||||||
|
|
||||||
|
<video src="./open-devcontainers-option2.m4v" controls></video>
|
||||||
|
Alternatively, you can also just use the compose files to start a stack and connect your VSCode instance to the backend container.
|
||||||
|
|
||||||
|
To do that, clone the repo and `cd` into this directory.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cd examples/devcontainers
|
||||||
|
docker compose up
|
||||||
|
```
|
||||||
|
|
||||||
|
The first time you run `docker compose up` it may take a few minutes as Docker will need to build images for the frontend and backend. Also there are some database migrations and seed data that need to happen. Those are handled by `backend/entrypoint.sh`. This is handled for you automatically since it is baked into the image. Once everything is up you should be able to access the frontend at [http://app.docker.localhost:8888]() and the backend at [http://app.docker.localhost:8888/api]()
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
## Developing
|
||||||
|
When running the `compose` stack, the backend/frontend node_modules are isolated from your host system. This is common in dev environment setups. In this case it is advised to use a Dev container. The following video demonstrates starting a dev container by using the VSCode plugin.
|
||||||
|
|
||||||
|
<video src="../../assets/open-dev-container.m4v" controls></video>
|
||||||
|
|
||||||
|
### Proxying and routes
|
||||||
|
You will notice that the backend is listening on `http://0.0.0.0:3333/` but the frontend is making requests to `/api/`. This is designed to mimic how you would deploy something like this in production where the backend would be behind a reverse proxy. Traefik has some really nice middleware that allows us to easily tell it to route requests destined for `/api` to `/`. The bit that handles that are these labels:
|
||||||
|
|
||||||
|
```compose
|
||||||
|
labels:
|
||||||
|
- "traefik.http.middlewares.strip-api-prefix.stripprefix.prefixes=/api"
|
||||||
|
- "traefik.http.routers.backend.rule=Host(`app.docker.localhost`) && PathPrefix(`/api`)"
|
||||||
|
- "traefik.http.routers.backend.middlewares=strip-api-prefix@docker"
|
||||||
|
```
|
||||||
|
|
||||||
|
We are defining a middleware named `strip-api-prefix` using the built in `strippreffix` Traefik middleware. We are then telling it to remove `/api` from any requests it handles. We then attach that to our backend router.
|
@ -1,32 +1,33 @@
|
|||||||
FROM node:lts-alpine3.22 AS base
|
FROM node:lts-alpine3.22 AS base
|
||||||
HEALTHCHECK --interval=5s --timeout=10s --start-period=5s --retries=5 \
|
HEALTHCHECK --interval=5s \
|
||||||
|
--timeout=10s \
|
||||||
|
--start-period=5s \
|
||||||
|
--retries=5 \
|
||||||
CMD sh -c 'wget --no-verbose --tries=1 --spider http://127.0.0.1:3333 || exit 1'
|
CMD sh -c 'wget --no-verbose --tries=1 --spider http://127.0.0.1:3333 || exit 1'
|
||||||
|
|
||||||
# All deps stage
|
# All deps stage
|
||||||
FROM base AS deps
|
FROM base AS deps
|
||||||
WORKDIR /app
|
WORKDIR /app/backend
|
||||||
ADD package.json package-lock.json ./
|
ADD package.json package-lock.json ./
|
||||||
RUN npm ci
|
RUN npm ci
|
||||||
|
|
||||||
FROM deps AS develop
|
FROM deps AS develop
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY dev-entrypoint.sh /entrypoint.sh
|
COPY entrypoint.sh /entrypoint.sh
|
||||||
RUN chmod +x /entrypoint.sh
|
RUN chmod +x /entrypoint.sh
|
||||||
RUN cat /entrypoint.sh
|
|
||||||
ENV NODE_ENV=development
|
|
||||||
EXPOSE 3333
|
EXPOSE 3333
|
||||||
ENTRYPOINT [ "/entrypoint.sh" ]
|
ENTRYPOINT [ "/entrypoint.sh" ]
|
||||||
|
|
||||||
# Production only deps stage
|
# Production only deps stage
|
||||||
FROM base AS production-deps
|
FROM base AS production-deps
|
||||||
WORKDIR /app
|
WORKDIR /app/backend
|
||||||
ADD package.json package-lock.json ./
|
ADD package.json package-lock.json ./
|
||||||
RUN npm ci --omit=dev
|
RUN npm ci --omit=dev
|
||||||
|
|
||||||
# Build stage
|
# Build stage
|
||||||
FROM base AS build
|
FROM base AS build
|
||||||
WORKDIR /app
|
WORKDIR /app/backend
|
||||||
COPY --from=deps /app/node_modules /app/node_modules
|
COPY --from=deps /app/backend/node_modules /app/backend/node_modules
|
||||||
ADD . .
|
ADD . .
|
||||||
RUN node ace build
|
RUN node ace build
|
||||||
|
|
||||||
@ -34,8 +35,8 @@ RUN node ace build
|
|||||||
FROM base
|
FROM base
|
||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY --from=production-deps /app/node_modules /app/node_modules
|
COPY --from=production-deps /app/backend/node_modules /app/backend/node_modules
|
||||||
COPY --from=build /app/build /app
|
COPY --from=build /app/backend/build /app
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
|
|
||||||
CMD ["node", "./bin/server.js"]
|
CMD ["node", "./bin/server.js"]
|
@ -0,0 +1,8 @@
|
|||||||
|
import type { HttpContext } from '@adonisjs/core/http'
|
||||||
|
import User from '#models/user'
|
||||||
|
export default class UsersController {
|
||||||
|
public async index({ request }: HttpContext) {
|
||||||
|
const page = request.input('page', 1)
|
||||||
|
return User.query().paginate(page)
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,10 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
|
cd /app/backend
|
||||||
|
cp .env.example .env
|
||||||
echo "starting up..."
|
echo "starting up..."
|
||||||
node ace generate:key
|
node ace generate:key
|
||||||
|
|
||||||
|
|
||||||
# Check for pending migrations by parsing output
|
# Check for pending migrations by parsing output
|
||||||
PENDING_MIGRATIONS=$(node ace migration:status | grep -ic 'pending')
|
PENDING_MIGRATIONS=$(node ace migration:status | grep -ic 'pending')
|
||||||
|
|
@ -8,7 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import router from '@adonisjs/core/services/router'
|
import router from '@adonisjs/core/services/router'
|
||||||
import UsersController from '#controllers/users_controller'
|
const UsersController = () => import('#controllers/users_controller')
|
||||||
router.get('users', [UsersController, 'index'])
|
router.get('users', [UsersController, 'index'])
|
||||||
router.get('/', async () => {
|
router.get('/', async () => {
|
||||||
return {
|
return {
|
17
examples/devcontainers/compose.override.yml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
services:
|
||||||
|
backend:
|
||||||
|
build:
|
||||||
|
context: backend
|
||||||
|
target: develop
|
||||||
|
volumes:
|
||||||
|
- ./backend:/app/backend/
|
||||||
|
- node_modules:/app/backend/node_modules
|
||||||
|
- frontend_node_modules:/app/frontend/node_modules
|
||||||
|
- ./frontend/:/app/frontend/
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
volumes:
|
||||||
|
node_modules: {}
|
||||||
|
frontend_node_modules: {}
|
@ -1,3 +1,4 @@
|
|||||||
|
name: fullstack
|
||||||
services:
|
services:
|
||||||
frontend:
|
frontend:
|
||||||
image: frontend:latest
|
image: frontend:latest
|
||||||
@ -5,8 +6,8 @@ services:
|
|||||||
context: ./frontend
|
context: ./frontend
|
||||||
target: develop
|
target: develop
|
||||||
volumes:
|
volumes:
|
||||||
- frontend_node_modules:/app/node_modules
|
- frontend_node_modules:/app/frontend/node_modules
|
||||||
- ./frontend/src:/app/src
|
- ./frontend/:/app/frontend/
|
||||||
labels:
|
labels:
|
||||||
- "traefik.http.routers.app.rule=Host(`app.docker.localhost`)"
|
- "traefik.http.routers.app.rule=Host(`app.docker.localhost`)"
|
||||||
reverse-proxy:
|
reverse-proxy:
|
||||||
@ -22,16 +23,10 @@ services:
|
|||||||
image: backend:latest
|
image: backend:latest
|
||||||
build:
|
build:
|
||||||
context: ./backend
|
context: ./backend
|
||||||
volumes:
|
|
||||||
- backend_node_modules:/backend/node_modules
|
|
||||||
- ./backend/:/backend
|
|
||||||
labels:
|
labels:
|
||||||
- "traefik.http.middlewares.strip-api-prefix.stripprefix.prefixes=/api"
|
- "traefik.http.middlewares.strip-api-prefix.stripprefix.prefixes=/api"
|
||||||
- "traefik.http.routers.backend.rule=Host(`app.docker.localhost`) && PathPrefix(`/api`)"
|
- "traefik.http.routers.backend.rule=Host(`app.docker.localhost`) && PathPrefix(`/api`)"
|
||||||
- "traefik.http.routers.backend.middlewares=strip-api-prefix@docker"
|
- "traefik.http.routers.backend.middlewares=strip-api-prefix@docker"
|
||||||
|
|
||||||
env_file:
|
|
||||||
- ./backend/.env
|
|
||||||
depends_on:
|
depends_on:
|
||||||
db:
|
db:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
@ -1,19 +1,16 @@
|
|||||||
FROM node:22-alpine AS base
|
FROM node:22-alpine AS base
|
||||||
WORKDIR /app
|
WORKDIR /app/frontend
|
||||||
COPY package.json yarn.lock ./
|
COPY package.json yarn.lock ./
|
||||||
RUN yarn install
|
RUN yarn install
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
FROM base AS build
|
FROM base AS build
|
||||||
WORKDIR /app
|
|
||||||
COPY --from=base /app/* .
|
|
||||||
RUN yarn build
|
RUN yarn build
|
||||||
|
|
||||||
FROM base AS develop
|
FROM base AS develop
|
||||||
COPY --from=base /app/ .
|
|
||||||
EXPOSE 5173
|
EXPOSE 5173
|
||||||
ENTRYPOINT [ "yarn", "dev", "--host", "0.0.0.0" ]
|
ENTRYPOINT [ "yarn", "dev", "--host", "0.0.0.0" ]
|
||||||
|
|
||||||
FROM nginx:alpine AS production
|
FROM nginx:alpine AS production
|
||||||
COPY --from=build /app/dist/ /usr/share/nginx/html
|
COPY --from=build /app/frontend/dist/ /usr/share/nginx/html
|
||||||
ENTRYPOINT [ "nginx", "-g", "daemon off;" ]
|
ENTRYPOINT [ "nginx", "-g", "daemon off;" ]
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
@ -18,21 +18,6 @@
|
|||||||
filter: drop-shadow(0 0 2em #61dafbaa);
|
filter: drop-shadow(0 0 2em #61dafbaa);
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes logo-spin {
|
|
||||||
from {
|
|
||||||
transform: rotate(0deg);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
transform: rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-reduced-motion: no-preference) {
|
|
||||||
a:nth-of-type(2) .logo {
|
|
||||||
animation: logo-spin infinite 20s linear;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.card {
|
.card {
|
||||||
padding: 2em;
|
padding: 2em;
|
||||||
}
|
}
|
@ -1,7 +1,6 @@
|
|||||||
import { useState, useEffect } from 'react'
|
import { useState, useEffect } from 'react'
|
||||||
import reactLogo from './assets/react.svg'
|
import reactLogo from './assets/react.svg'
|
||||||
import dockerLogo from './assets/docker.svg'
|
import dockerLogo from './assets/docker.svg'
|
||||||
import viteLogo from '/vite.svg'
|
|
||||||
import './App.css'
|
import './App.css'
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
@ -38,18 +37,15 @@ function App() {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div>
|
<div>
|
||||||
<a href="https://vite.dev" target="_blank" rel="noreferrer">
|
|
||||||
<img src={viteLogo} className="logo" alt="Vite logo" />
|
|
||||||
</a>
|
|
||||||
<a href="https://react.dev" target="_blank" rel="noreferrer">
|
<a href="https://react.dev" target="_blank" rel="noreferrer">
|
||||||
<img src={reactLogo} className="logo react" alt="React logo" />
|
<img src={reactLogo} className="logo react" alt="React logo" />
|
||||||
</a>
|
</a>
|
||||||
<a href="https://docker.com" target="_blank" rel="noreferrer">
|
<a href="https://docker.com" target="_blank" rel="noreferrer">
|
||||||
<img src={dockerLogo} className="logo docker" alt="Docker logo" />
|
<img src={dockerLogo} className="logo docker" alt="Docker logo" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h1>Vite + React + Docker + Traefik</h1>
|
<h1>React + Docker + Traefik</h1>
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.6 KiB |
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 170 KiB After Width: | Height: | Size: 170 KiB |
BIN
examples/devcontainers/open-devcontainers-option1.m4v
Normal file
BIN
examples/devcontainers/open-devcontainers-option2.m4v
Normal file
@ -1,25 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Fullstack DevContainer",
|
|
||||||
"dockerComposeFile": ["../docker-compose.yml"],
|
|
||||||
"service": "frontend",
|
|
||||||
"workspaceFolder": "/app",
|
|
||||||
"shutdownAction": "stopCompose",
|
|
||||||
"forwardPorts": [80, 8080],
|
|
||||||
"settings": {
|
|
||||||
"terminal.integrated.defaultProfile.linux": "bash"
|
|
||||||
},
|
|
||||||
"mounts": [
|
|
||||||
"source=frontend_node_modules,target=/app/node_modules,type=volume",
|
|
||||||
"source=backend_node_modules,target=/backend/node_modules,type=volume",
|
|
||||||
"source=${localWorkspaceFolder}/backend,target=/backend,type=bind"
|
|
||||||
],
|
|
||||||
"postCreateCommand": "npm install && cd /backend && npm install",
|
|
||||||
"customizations": {
|
|
||||||
"vscode": {
|
|
||||||
"extensions": [
|
|
||||||
"dbaeumer.vscode-eslint",
|
|
||||||
"esbenp.prettier-vscode"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
# Overview
|
|
||||||
This is a practical example of a "basic" fullstack application. This application has been fully containerized to be run locally in development mode as well as for deployment to production. It is composed of the following services:
|
|
||||||
|
|
||||||
- frontend - Basic React app bootstrapped with `yarn create vite`
|
|
||||||
- backend - AdonisJS API Backend [https://adonisjs.com]()
|
|
||||||
- database - Postgres database
|
|
||||||
- reverse_proxy - Traefik ingress controller handling reverse proxy for the frontend and backend applications.
|
|
||||||
|
|
||||||
## Getting Started
|
|
||||||
Clone the repo and `cd` into the `compose` directory.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
cp backend/.env.example backend/.env
|
|
||||||
docker compose up
|
|
||||||
```
|
|
||||||
|
|
||||||
The first time you run `docker compose up` it may take a few minutes as Docker will need to build images for the frontend and backend. Also there are some database migrations and seed data that need to happen. Those are handled by `backend/dev-entrypoint.sh`. This is handled for you automatically since it is baked into the image. Once everything is up you should be able to access the frontend at [http://app.docker.localhost:8888]() and the backend at [http://app.docker.localhost:8888/api]()
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
## Developing
|
|
||||||
When running the `compose` stack, the backend node_modules are isolated from your host system. This is common in dev environment setups. In this case it is advised to use a Dev container. The following video demonstrates starting a dev container by using the VSCode plugin.
|
|
||||||
|
|
||||||
<video src="../../assets/open-dev-container.m4v" controls></video>
|
|
||||||
|
|
||||||
### Proxying and routes
|
|
||||||
You will notice that the backend is listening on `http://0.0.0.0:3333/` but the frontend is making requests to `/api/`. This is designed to mimic how you would deploy something like this in production where the backend would be behind a reverse proxy. Traefik has some really nice middleware that allows us to easily tell it to route requests destined for `/api` to `/`. The bit that handles that are these labels:
|
|
||||||
|
|
||||||
```compose
|
|
||||||
labels:
|
|
||||||
- "traefik.http.middlewares.strip-api-prefix.stripprefix.prefixes=/api"
|
|
||||||
- "traefik.http.routers.backend.rule=Host(`app.docker.localhost`) && PathPrefix(`/api`)"
|
|
||||||
- "traefik.http.routers.backend.middlewares=strip-api-prefix@docker"
|
|
||||||
```
|
|
||||||
|
|
||||||
We are defining a middleware named `strip-api-prefix` using the built in `strippreffix` Traefik middleware. We are then telling it to remove `/api` from any requests it handles. We then attach that to our backend router.
|
|
@ -1,8 +0,0 @@
|
|||||||
import type { HttpContext } from '@adonisjs/core/http'
|
|
||||||
import User from '#models/user'
|
|
||||||
export default class UsersController {
|
|
||||||
public async index({ request }: HttpContext) {
|
|
||||||
const page = request.input('page', 1)
|
|
||||||
return User.query().paginate(page)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
---
|
|
||||||
services:
|
|
||||||
backend:
|
|
||||||
build:
|
|
||||||
context: backend
|
|
||||||
target: develop
|
|
||||||
volumes:
|
|
||||||
- ./backend:/app
|
|
||||||
- node_modules:/app/node_modules
|
|
||||||
depends_on:
|
|
||||||
db:
|
|
||||||
condition: service_healthy
|
|
||||||
volumes:
|
|
||||||
node_modules: {}
|
|
BIN
slides/images/pexels-joshsorenson-1714208.jpg
Normal file
After Width: | Height: | Size: 1.2 MiB |
BIN
slides/images/pexels-luis-gomes-166706-546819.jpg
Normal file
After Width: | Height: | Size: 132 KiB |
BIN
slides/images/pexels-markusspiske-1089438.jpg
Normal file
After Width: | Height: | Size: 2.5 MiB |
179
slides/slides.md
@ -5,15 +5,13 @@ theme: seriph
|
|||||||
# like them? see https://unsplash.com/collections/94734566/slidev
|
# like them? see https://unsplash.com/collections/94734566/slidev
|
||||||
background: https://cover.sli.dev
|
background: https://cover.sli.dev
|
||||||
# some information about your slides (markdown enabled)
|
# some information about your slides (markdown enabled)
|
||||||
title: Welcome to Slidev
|
title: Demystifying Docker - SCS 2025
|
||||||
info: |
|
info: |
|
||||||
## Slidev Starter Template
|
## The basics of containerization and beyond by Mike Conrad
|
||||||
Presentation slides for developers.
|
Scenic City Summit 2025
|
||||||
|
|
||||||
Learn more at [Sli.dev](https://sli.dev)
|
Learn more at [Hackanooga](https://hackanooga.com/scs)
|
||||||
# apply unocss classes to the current slide
|
|
||||||
class: text-center
|
class: text-center
|
||||||
# https://sli.dev/features/drawing
|
|
||||||
drawings:
|
drawings:
|
||||||
persist: false
|
persist: false
|
||||||
# slide transition: https://sli.dev/guide/animations.html#slide-transitions
|
# slide transition: https://sli.dev/guide/animations.html#slide-transitions
|
||||||
@ -35,6 +33,7 @@ Mike Conrad - SCS 2025
|
|||||||
<p><a href="https://hackanooga.com/scs">https://hackanooga.com/scs</a></p>
|
<p><a href="https://hackanooga.com/scs">https://hackanooga.com/scs</a></p>
|
||||||
<small>Includes slide deck, and repo with examples</small>
|
<small>Includes slide deck, and repo with examples</small>
|
||||||
<img src="./images/talk.jpg" width="200">
|
<img src="./images/talk.jpg" width="200">
|
||||||
|
Connect with me on LinkedIn: https://linkedin.com/enxoco
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="abs-br m-6 text-xl">
|
<div class="abs-br m-6 text-xl">
|
||||||
@ -52,36 +51,21 @@ The last comment block of each slide will be treated as slide notes. It will be
|
|||||||
|
|
||||||
---
|
---
|
||||||
transition: fade-out
|
transition: fade-out
|
||||||
layout: center
|
layout: statement
|
||||||
|
background: ./images/pexels-markusspiske-1089438.jpg
|
||||||
---
|
---
|
||||||
|
# The 3 universal constants in programming
|
||||||
# Who is this for?
|
<v-click>
|
||||||
|
<h2>1) The speed of light</h2>
|
||||||
## About you
|
</v-click>
|
||||||
- Some experience with Docker/containers
|
<v-click>
|
||||||
- Familiarity with Linux/BASH
|
<h2>2) "It's more complicated than you think"</h2>
|
||||||
- Want to better understand how containers work
|
</v-click>
|
||||||
- Want to learn new techniques for automation
|
<v-click>
|
||||||
|
<h2>3) "It works on my machine"</h2>
|
||||||
---
|
<br />
|
||||||
transition: fade-out
|
<small>Source: <a href="https://www.linkedin.com/posts/robertroskam_the-3-universal-constants-in-programming-activity-7339260450074775553-ofik?utm_source=share&utm_medium=member_desktop&rcm=ACoAACZXneYB_uWiOE0T9VO3caUkn7m0ZMrRS_o">Some random guy on the internet</a></small>
|
||||||
layout: center
|
</v-click>
|
||||||
---
|
|
||||||
|
|
||||||
## Follow Along
|
|
||||||
**Example Repo** - https://hackanooga.com/scs
|
|
||||||
|
|
||||||
**Prerequisites**
|
|
||||||
- Docker
|
|
||||||
- VSCode
|
|
||||||
- Git
|
|
||||||
- yarn/npm/pnpm,etc (For viewing slides)
|
|
||||||
|
|
||||||
### VSCode plugins
|
|
||||||
- [Official Docker Plugin](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-docker)
|
|
||||||
- [Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers)
|
|
||||||
- [Container Tools](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-containers)
|
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
transition: fade-out
|
transition: fade-out
|
||||||
@ -90,18 +74,42 @@ layout: center
|
|||||||
|
|
||||||
<img src="./images/docker-meme.jpg" width="300"/>
|
<img src="./images/docker-meme.jpg" width="300"/>
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
transition: fade-out
|
transition: fade-out
|
||||||
layout: center
|
layout: image-right
|
||||||
|
image: ./images/pexels-markusspiske-1089438.jpg
|
||||||
---
|
---
|
||||||
|
|
||||||
## Common Use cases for containers
|
# Who is this for?
|
||||||
- Reproducible dev environments
|
|
||||||
- Testing in CI/CD environments
|
|
||||||
- Better "Portability" of application code
|
|
||||||
- Snapshot of application code at specific point in time
|
|
||||||
|
|
||||||
|
## About you
|
||||||
|
- Some experience with Docker/containers
|
||||||
|
- Familiarity with Linux/BASH/zsh, etc
|
||||||
|
- Want to better understand how containers work
|
||||||
|
- Want to learn new techniques for automation
|
||||||
|
|
||||||
|
---
|
||||||
|
transition: fade-out
|
||||||
|
layout: image-left
|
||||||
|
image: ./images/pexels-joshsorenson-1714208.jpg
|
||||||
|
---
|
||||||
|
|
||||||
|
## Follow Along
|
||||||
|
<small>Visit the link to check out the sample Git repository.</small>
|
||||||
|
|
||||||
|
**Example Repo** - https://hackanooga.com/scs
|
||||||
|
|
||||||
|
**Prerequisites**
|
||||||
|
- Docker Engine (Linux) or Docker Desktop (Windows/MacOS)
|
||||||
|
- VSCode
|
||||||
|
- Git
|
||||||
|
- yarn, npm or pnpm (for viewing slides)
|
||||||
|
|
||||||
|
### VSCode plugins
|
||||||
|
- [Official Docker Plugin](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-docker)
|
||||||
|
- [Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers)
|
||||||
|
- [Container Tools](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-containers)
|
||||||
|
|
||||||
---
|
---
|
||||||
transition: fade-out
|
transition: fade-out
|
||||||
@ -126,13 +134,13 @@ layout: center
|
|||||||
|
|
||||||
## Containers vs Virtual Machines
|
## Containers vs Virtual Machines
|
||||||
|
|
||||||
| Feature | VM | Container |
|
| Feature | VMs | Containers |
|
||||||
|------------------|----------------|------------------|
|
|------------------|-----------------------|------------------------------|
|
||||||
| Boot time | Minutes | Seconds |
|
| Boot time | Minutes | Seconds |
|
||||||
| Resource usage | Heavy | Lightweight |
|
| Resource usage | Heavy | Lightweight |
|
||||||
| Isolation | Strong | Process-level |
|
| Isolation | Strong | Process-level |
|
||||||
| Portability | Medium | Very High |
|
| Portability | Medium | Very High |
|
||||||
|
| Operating System | Needs full OS install | Uses host OS/kernel features |
|
||||||
In reality we use containers and vm's together. Containers run inside of VM's for better security and isolation, especially in cloud and multi tenant environments.
|
In reality we use containers and vm's together. Containers run inside of VM's for better security and isolation, especially in cloud and multi tenant environments.
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -142,26 +150,17 @@ layout: center
|
|||||||
|
|
||||||
## What is Docker?
|
## What is Docker?
|
||||||
|
|
||||||
|
- A tool to build and run containers
|
||||||
- Written in GO
|
- Written in GO
|
||||||
- Uses Client/Server model with REST API (`docker cli` and `dockerd`)
|
- Uses Client/Server model with REST API (`docker cli` and `dockerd`)
|
||||||
- Eco system of tools (Compose, Swarm, etc)
|
- Eco system of tools (Compose, Swarm, etc)
|
||||||
- Public Image Registry (Dockerhub)
|
- Public Image Registry (Dockerhub)
|
||||||
- Docker client typically runs on same machine as server but doesn't have to
|
- Docker client typically runs on same machine as server but doesn't have to
|
||||||
|
- Uses Linux kernal features like:
|
||||||
---
|
- Namespaces
|
||||||
transition: fade-out
|
- cgroups
|
||||||
layout: center
|
- Union file systems
|
||||||
---
|
- Containers are just processes
|
||||||
## What is Docker?
|
|
||||||
|
|
||||||
- A tool to build and run containers
|
|
||||||
- Containers are exclusive to Linux
|
|
||||||
- Docker engine runs containers using Linux features like:
|
|
||||||
- Namespaces
|
|
||||||
- cgroups
|
|
||||||
- Union file systems
|
|
||||||
- Container runs from an image layered with base image and application code
|
|
||||||
|
|
||||||
---
|
---
|
||||||
transition: fade-out
|
transition: fade-out
|
||||||
layout: center
|
layout: center
|
||||||
@ -193,24 +192,42 @@ layout: center
|
|||||||
|
|
||||||
---
|
---
|
||||||
transition: fade-out
|
transition: fade-out
|
||||||
layout: center
|
layout: two-cols-header
|
||||||
---
|
---
|
||||||
|
|
||||||
## Bind/Volume Mounts
|
<div class="flex items-center flex-col">
|
||||||
|
<h1 class="ml-5">Bind/Volume Mounts</h1>
|
||||||
|
|
||||||
- 2 most common storage mechanisms
|
<p>2 most common storage mechanisms<br />Different use cases and security implications</p>
|
||||||
- Different use cases and security implications
|
</div>
|
||||||
|
::left::
|
||||||
|
## Bind Mounts
|
||||||
|
|
||||||
|
- Created/managed by user.
|
||||||
|
- Files from host mounted directly into container.
|
||||||
|
- Container processes can modify files on host system.
|
||||||
|
- Strongly tied to the host.
|
||||||
|
- Best for things like dev containers.
|
||||||
|
|
||||||
|
::right::
|
||||||
|
|
||||||
|
|
||||||
|
## Volume mounts
|
||||||
|
- Created/managed by Docker Daemon.
|
||||||
|
- Data is stored on host filesystem.
|
||||||
|
- Used for persistent data.
|
||||||
|
|
||||||
|
<!--
|
||||||
|
It is possible to modify the data directly via normal tools but unsupported and can cause unintended side-effects due to the overlayfs storage driver.
|
||||||
|
An example would be creating a postgres volume for persistent database storage.
|
||||||
|
-->
|
||||||
---
|
---
|
||||||
transition: fade-out
|
transition: fade-out
|
||||||
layout: center
|
layout: center
|
||||||
|
image: 'https://unsplash.com/collections/oGE7TYSLt3I/software-development
|
||||||
|
equal: false
|
||||||
|
left: false
|
||||||
---
|
---
|
||||||
## Bind Mounts
|
|
||||||
|
|
||||||
- Mounting files/directories from the host machine directly into a container (merged overlayfs layer).
|
|
||||||
- Processes inside container can modify files on host system.
|
|
||||||
- Bind mounts are strongly tied to the host
|
|
||||||
- Best for things like dev containers where you need to mount source code into container and have hot reload, etc.
|
|
||||||
|
|
||||||
## Bind Mount Example
|
## Bind Mount Example
|
||||||
```bash
|
```bash
|
||||||
@ -264,20 +281,6 @@ $ docker volume inspect postgresData
|
|||||||
- Docker creates a volume named postgresData and mounts that directory inside the container.
|
- Docker creates a volume named postgresData and mounts that directory inside the container.
|
||||||
<!-- https://docs.docker.com/engine/storage/bind-mounts/ -->
|
<!-- https://docs.docker.com/engine/storage/bind-mounts/ -->
|
||||||
|
|
||||||
---
|
|
||||||
transition: fade-out
|
|
||||||
layout: center
|
|
||||||
---
|
|
||||||
|
|
||||||
## Volume mounts
|
|
||||||
- Created and managed by the Docker Daemon
|
|
||||||
- Volume data is stored on host filesystem but managed by Docker.
|
|
||||||
- Used for persistent data.
|
|
||||||
|
|
||||||
<!--
|
|
||||||
It is possible to modify the data directly via normal tools but unsupported and can cause unintended side-effects due to the overlayfs storage driver.
|
|
||||||
An example would be creating a postgres volume for persistent database storage.
|
|
||||||
-->
|
|
||||||
|
|
||||||
---
|
---
|
||||||
transition: fade-out
|
transition: fade-out
|
||||||
@ -330,7 +333,7 @@ EXPOSE 5173
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ docker build -t react .
|
$ docker build -t react .
|
||||||
$ docker run --rm -P react
|
$ docker run --rm -p 5173:5173 react
|
||||||
```
|
```
|
||||||
<!--
|
<!--
|
||||||
Run docker image and demonstrate dev container functionality. Attach to the running container
|
Run docker image and demonstrate dev container functionality. Attach to the running container
|
||||||
|