1æéã§ããã£ãŠåŠã¶Docker
Dockerãè§ŠããªããåŠãã§ãããåå¿è
åãã®èšäºã§ãã
çšèªã®è§£èª¬çã¯ã»ãšãã©ããã«ããšã«ããè§Šã£ãŠã¿ãããšãç®çãšããŠããŸãã
- Phase 1: Dockerã®åºæ¬
ã³ãã³ãã詊ããªããåºæ¬æäœãåŠã³ãŸãã - Phase 2: Dockerfileãããå°ãæžããŠã¿ã
Dockerfileã䜿ã£ãŠãç°¡åãªWebã¢ããªã±ãŒã·ã§ã³ãäœæããŸãã - Phase 3: Docker Composeã䜿ã£ãŠã¿ã
Docker Composeã䜿ã£ãŠãè€æ°ã®ã³ã³ãããäžæ¬ç®¡çããŸãã
Phase 1: Dockerã®åºæ¬
Dockerã®åºæ¬çãªæäœã詊ããŠã¿ãŸãã
ãããžã§ã¯ããã©ã«ãã®äœæ
次ã®ã³ãã³ããå®è¡ããŠããããžã§ã¯ããã©ã«ããäœæããŸãã
mkdir docker-hands-on
cd docker-hands-on
æãã·ã³ãã«ãªã³ã³ããã®äœæãšå®è¡
以äžã®ã³ãã³ããå®è¡ããŠã¿ãŸãããã
docker run -it alpine:latest
ãã®ã³ãã³ãã¯ãDocker Hubããalpineã€ã¡ãŒãžãããŠã³ããŒãããŠå®è¡ããŸãã
-itãªãã·ã§ã³ã¯ã€ã³ã¿ã©ã¯ãã£ãã¢ãŒããæå®ããã³ã³ããå
ã§å¯Ÿè©±çã«ã³ãã³ããå®è¡ã§ããŸãã
> echo "hello"
hello
> exit # ã³ã³ããã®å€ã«åºã
Dockerfileã®äœæ
èªåèªèº«ã®Dockerã€ã¡ãŒãžãäœæããããã«ã¯Dockerfileã䜿çšããŸãã
以äžã¯ãšã£ãŠãã·ã³ãã«ãªDockerfileã®äŸã§ãã
touch Dockerfile
vim Dockerfile
äœã£ãDokcerfileã«ä»¥äžã®å 容ãèšè¿°ããŸãã
FROM alpine:latest
-
FROMã¯ããŒã¹ã€ã¡ãŒãžãæå®ããããã®ããŒã¯ãŒã -
alpine:latestã¯ããŒã¹ã€ã¡ãŒãžã®åå
Dockerfileã®è©³çްã«ã€ããŠã¯ãPhase 2ã§åŠã³ãŸãã
Dockerã€ã¡ãŒãžã®ãã«ããšå®è¡
次ã«ããã«ãããŠå®è¡ããŠã¿ãŸãããã
docker build -t myalpine .
-tãªãã·ã§ã³ã¯ã¿ã°ä»ããè¡ãããã®ãã®ã§ãã
ã¿ã°ãæå®ããªãå Žåã¯ãã©ã³ãã ãªæååãã¿ã°ãšããŠä»äžãããŸãã
ã¿ã°ãæå®ããŠãã³ã³ãããå®è¡ããŠã¿ãŸãããã
docker run -it myalpine
Alpine Linuxãæ£ããåäœããŠãããã確èªããŠã¿ãŸãããã
cat /etc/os-release
確èªãçµãã£ãããã³ã³ããããåºãŸãããã
exit
ã³ã³ããã®åæ¢ãšåé€
Docker Desktopã®Containersããã§ãã¯ãããšãã³ã³ããã確èªããããšãã§ããŸãã
ãã®èšäºéãã«ãã£ãŠããå ŽåãalipineãšmyalpineãšããIMAGEã§äœãããã³ã³ããã忢ããŠããã¯ãã§ãã
ãããã³ã³ããã¯ãGUIã§ãCLIã§ãåé€ããããšãã§ããŸãã
ãŸããã³ã³ããã忢ããæã«èªåã§åé€ãããå Žåã¯ã--rmãªãã·ã§ã³ã䜿çšããŸãã
docker run --rm -it myalpine
exitããåŸã«ã³ã³ããã¯åé€ãããŠããã¯ãã§ãã
--rmãªãã·ã§ã³ãä»ããã«ã³ã³ãããå®è¡ã忢ãç¹°ãè¿ããŠãããšãåããŠããªãã³ã³ãããã©ãã©ãæºãŸã£ãŠããã®ã§æ³šæããŠäžããã
ããã¯ã°ã©ãŠã³ãã§ã®å®è¡ãšã³ã³ãããžã®ã¢ã¯ã»ã¹
ããã¯ã°ã©ãŠã³ãã§ã³ã³ãããå®è¡ããããšãå¯èœã§ãã以äžã®ã³ãã³ããå®è¡ããŸãã
docker run --rm -d -it myalpine
-dãªãã·ã§ã³ã¯ãã¿ããã¢ãŒãïŒããã¯ã°ã©ãŠã³ãã§å®è¡ïŒãæå®ããŸãã
ãããŠãdocker execã³ãã³ãã§ã³ã³ããã«ã¢ã¯ã»ã¹ããããšãã§ããŸãã
docker exec -it <container id> sh
-itãªãã·ã§ã³ã¯ãdocker runã®æãšåæ§ã«ãã€ã³ã¿ã©ã¯ãã£ãã¢ãŒããæå®ããŸãã
ã³ã³ããIDã確èªããã«ã¯ã以äžã®ã³ãã³ããå®è¡ããŸããåºåãããäžèЧãã<container id>ã確èªããŸãã
docker ps
ããã¯ã°ã©ãŠã³ãã®ã³ã³ããã忢/åé€ããã«ã¯ããŸããã³ã³ããã忢ããŸãã--rmãªãã·ã§ã³ã䜿çšããŠããå Žåãã³ã³ããã¯åæ¢ãšåæã«èªåçã«åé€ãããŸãã
docker stop <container id>
ã³ã³ãããæåã§åé€ããã«ã¯ãdocker rmã³ãã³ãã䜿çšããŸãã
docker rm <container id>
Phase 2: Dockerfileãããå°ãæžããŠã¿ã
ä»åºŠã¯ãDokceräžã§expressã䜿ã£ãç°¡åãªWebã¢ããªã±ãŒã·ã§ã³ãäœæããŠã¿ãŸãããã
mkdir front
cd front
npm init -y
npm install express
index.jsãäœæããŸãã
// Expressã©ã€ãã©ãªãã€ã³ããŒã
const express = require('express');
// Expressãåæå
const app = express();
// ãªãã¹ã³ããããŒããå®çŸ©
const port = 3000;
// ã«ãŒããã¹('/')ãžã®GETãªã¯ãšã¹ãã®ã«ãŒããã³ãã©ãå®çŸ©
app.get('/', (req, res) => {
res.send('Hello, Docker!');
});
// æå®ããããŒãã§ã¢ããªããªãã¹ã³
app.listen(port, () => {
console.log(`App running on http://localhost:${port}`);
});
DockerfileãäœæããŸã
å
ã»ã©ã®DockerfileãšéããããŸããŸãªã³ãã³ããå®è¡ãããŠããŸãã
ãã ããã£ãŠããããšã¯åçŽãªã®ã§ãã³ããããåŸã«ããããã®ã³ã¡ã³ããèªãã§ã¿ãŠãã ããã
# ããŒã¹ã€ã¡ãŒãžãšããŠNode.js 14ã®ã€ã¡ãŒãžãéžæ
FROM node:14-slim
# ã³ã³ããå
ã®äœæ¥ãã£ã¬ã¯ããªã/appã«èšå®
WORKDIR /app
# package.jsonãšpackage-lock.jsonãã³ã³ããå
ã®äœæ¥ãã£ã¬ã¯ããªã«ã³ããŒ
COPY package*.json ./
# ã¢ããªã±ãŒã·ã§ã³ã®äŸåé¢ä¿ãã€ã³ã¹ããŒã«ããããã«ã³ã³ããå
ã§npm installãå®è¡
RUN npm install
# ã¢ããªã±ãŒã·ã§ã³ã®ãœãŒã¹ã³ãŒãã®æ®ããäœæ¥ãã£ã¬ã¯ããªã«ã³ããŒ
COPY . .
# ã¢ããªã±ãŒã·ã§ã³ã¯ããŒã3000ã§ãªãã¹ã³ããã®ã§ãDockerã«ãã®ããŒããå
¬éããããã«æç€º
EXPOSE 3000
# ã¢ããªã±ãŒã·ã§ã³ãèµ·åããã³ãã³ã
CMD [ "node", "index.js" ]
.dockerignoreãã¡ã€ã«ãäœæããŸã
ããã¯ãDockerã€ã¡ãŒãžããã«ãããéã«ç¡èŠãããã¡ã€ã«ãæå®ããããã®ãã®ã§ãã
node_modules
npm-debug.log
ããã§ã¯ãDockerã€ã¡ãŒãžããã«ãããŠã¿ãŸãããã
docker build -t front-demo .
次ã«ãã³ã³ãããå®è¡ããŠã¿ãŸãããã
ä»åã¯ã-pãªãã·ã§ã³ã䜿çšããŠããã¹ãã®ããŒã3000ãã³ã³ããã®ããŒã3000ã«ãããã³ã°ããŸãã
ããããããšã§ããã¹ãããã³ã³ããã«ã¢ã¯ã»ã¹ããããšãã§ããŸãã
docker run -d --rm -p 3000:3000 front-demo
localhost:3000ã«ã¢ã¯ã»ã¹ããŠã¿ãŸãããã
確èªã§ããããCLIãGUIã§ã³ã³ããã¯åæ¢ããšããŠäžããã
Phase 3: Docker Composeã䜿ã£ãŠã¿ãã
Dokcerã§ã¯ã1ããã»ã¹ã®ã¿ãå®è¡ããã³ã³ãããäœæããããšãæšå¥šãããŠããŸãã
ããã§ã¯ãå
ã»ã©ã®Expressã¢ããªã±ãŒã·ã§ã³ã«å ããŠãChatGPTã䜿ã£ãAPIãå®è¡ããã³ã³ãããäœæããŠãè€æ°ã®ã³ã³ãããåæã«å®è¡ããæ¹æ³ã詊ããŠã¿ãŸãã
OpenAIã®APIã䜿ã£ãã¢ããªã§ããã䜿ãå¿
èŠã¯å
šããªãã®ã§é©å®æžãæããŠäžããã
ãŸãã¯ããããžã§ã¯ãã«ãŒãã«æ»ã£ãŠãAPIçšã®ãã©ã«ããäœæããŸãã
cd ../
mkdir back
cd back
Flaskã䜿ã£ãç°¡åãªWebAPIãäœæããŠã¿ãŸãããã
ãŸãã¯ãrequirements.txtãäœæããå¿
èŠãªPythonããã±ãŒãžããªã¹ãã¢ããããŸãã
flask
openai
ããã§ã¯ãpip installããå¿
èŠã¯ãããŸããã
Dockerfileã§èªåçã«ã€ã³ã¹ããŒã«ãããããã«ãã®ããšèšè¿°ããŸãã
次ã«ãapp.pyãäœæããŸãã
from flask import Flask, Response, request
import openai
import os
import json
app = Flask(__name__)
@app.route('/', methods=['GET'])
def generate():
openai.api_key = os.getenv('OPENAI_KEY')
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[
{
"role": "user",
"content": f"Please generate one sentence of a joke in Japanese."
}
],
temperature=1,
max_tokens=256,
top_p=1,
frequency_penalty=0,
presence_penalty=0
)
result = json.dumps(response.choices[0].message.content.strip(), ensure_ascii=False)
return Response(result, content_type='application/json; charset=utf-8')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=4000)
æåŸã«DockerfileãäœæããŸãã
# ããŒã¹ãšãªãã€ã¡ãŒãžã®èšå®
FROM python:3.11-slim
# ã¯ãŒãã³ã°ãã£ã¬ã¯ããªã®èšå®
WORKDIR /app
# äŸåé¢ä¿ãªã¹ãã®ã³ããŒ
COPY requirements.txt requirements.txt
# äŸåé¢ä¿ã®ã€ã³ã¹ããŒã«
RUN pip install -r requirements.txt
# ãœãŒã¹ã³ãŒãã®ã³ããŒ
COPY . .
# ããŒã4000ãå
Ž
EXPOSE 4000
# å®è¡ã³ãã³ã
CMD [ "python", "app.py" ]
Dockefileãåºæ¥äžãã£ããããã«ãã§ãã
docker build -t back-demo .
å®è¡ã³ãã³ãã§ã¯ãOpenAIã®APIã䜿ãããã«APIããŒãæž¡ããªããã°ãªããŸããã
ç°å¢å€æ°ãã³ã³ããã«æž¡ãããã«ã¯ã-eãªãã·ã§ã³ãdocker runã³ãã³ããšå
±ã«äœ¿çšããŸãã
docker run -p 4000:4000 -d --rm -e OPENAI_KEY=your_openai_key back-demo
ãããã¯ãã·ã§ã«å€æ°ããAPIããŒãèªã¿èŸŒãå Žåã¯ä»¥äžã®ããã«ããŸãïŒ
docker run -p 4000:4000 -d --rm -e OPENAI_KEY=${OPENAI_API_KEY} back-demo
ã«ã¢ã¯ã»ã¹ããŠã¿ãŸãããã
æ¥æ¬èªã®ç²ãªãžã§ãŒã¯ã衚瀺ãããã¯ãã§ãã
次ã«é²ãåã«ãã³ã³ããã忢ããŠãããŠäžããã
次ã«ãããã³ããšã³ãéšåãæçŽãããŸãã
ãã¹ããã·ã³ã§ãfrontãã©ã«ãã«ç§»åããaxiosãinstallããŠäžããã
cd ../
cd front
npm install axios
次ã«ãindex.jsãæžãæããŸãã
docker-hands-on/front/index.js
const express = require('express');
const axios = require('axios');
const app = express();
const port = 3000;
app.use(express.static('public'));
app.post('/api', async (req, res) => {
try {
const response = await axios.get('http://api:4000');
res.send(response.data);
} catch (error) {
console.error(`Error: ${error}`);
}
});
app.listen(port, () => {
console.log(`App running on http://localhost:${port}`);
});
frontãã£ã¬ã¯ããªã®äžã«ãpublicãã£ã¬ã¯ããªãäœæãããã®äžã«index.htmlãäœæããŸãã
docker-hands-on/front
mkdir public
touch public/index.html
vim public/index.html
docker-hands-on/front/public/index.html
<!DOCTYPE html>
<html>
<head>
<title>Hello World Page</title>
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.16/dist/tailwind.min.css" rel="stylesheet">
<script src="https://unpkg.com/htmx.org@1.6.1"></script>
</head>
<body class="grid items-center justify-items-center h-screen gap-4 bg-gray-200">
<div id="response" class="text-center">Waiting for response...</div>
<button class="px-4 py-2 font-bold text-white bg-blue-500 rounded hover:bg-blue-700" hx-post="/api" hx-trigger="click" hx-swap="innerHTML" hx-target="#response">Click me!</button>
</body>
</html>
ããã³ããšã³ãã¢ããªã±ãŒã·ã§ã³ã®å
å®¹ãæžãæããã®ã§ãDockerã€ã¡ãŒãžãäœãçŽããŸãã
docker-hands-on/front
docker build -t front-demo .
æåŸã«ãããã³ããšã³ããšããã¯ãšã³ãã®ã³ã³ãããåãDockerãããã¯ãŒã¯ã«æ¥ç¶ããŸããããã«ãããããã³ããšã³ãããããã¯ãšã³ãã®APIãåŒã³åºãããšãã§ããŸãã
以äžã®ã³ãã³ãã§Dockerãããã¯ãŒã¯ãäœæããŸãïŒ
docker network create network-demo
ãããŠã以äžã®ã³ãã³ãã§ããã³ããšã³ããšããã¯ãšã³ãã®ã³ã³ãããåããããã¯ãŒã¯ã«æ¥ç¶ããŸãïŒ
docker run --rm -d -p 3000:3000 --network network-demo --network-alias web front-demo
docker run --rm -d -p 4000:4000 -d -e OPENAI_KEY=${OPENAI_API_KEY} --network network-demo --network-alias api back-demo
ãã£ãšãããŸã§æ¥ãŸããã
æåŸã«ãã®Phaseã®ã¡ã€ã³ãã£ãã·ã¥ã§ãã
dockerã³ãã³ãã®ãªãã·ã§ã³ãå€ããŠå€§å€ã«ãªã£ãŠããã®ã§ãDocker Composeã䜿çšããŠãããããããç°¡åã«ç®¡çã§ããããã«ããŠã¿ãŸãããã
ãããžã§ã¯ãã«ãŒãã«docker-compose.ymlãšãããã¡ã€ã«ãäœããŸãã
ã³ã¡ã³ããããä¿®æ£ã
çŸåšã¯ãdocker-compose.ymlã§ã¯ãªããcompose.ymlãæšå¥šãšã®ããšã
version: '3.8' # ä¿®æ£ïŒversionã¯(optional)ãšãªã£ãŠãããå¿
é ã§ã¯ãªãã
services:
front:
build:
context: ./front
ports:
- 3000:3000
networks:
app-network:
aliases:
- web
back:
build:
context: ./back
ports:
- 4000:4000
environment:
- OPENAI_KEY=${OPENAI_API_KEY} #ç°å¢å€æ°ã«èšå®ããŠãªãå Žåã¯ãçŽã§APIããŒãæžããŠäžããã
networks:
app-network:
aliases:
- api
networks:
app-network:
name: network-demo
compose.ymlãã¡ã€ã«ãäœæãããã以äžã®ã³ãã³ãã§ã³ã³ãããèµ·åããŸãïŒ
ã³ã¡ã³ããããä¿®æ£ã
以åã¯ãdocker-compose ããããããããã§ããããçŸåšã¯ãdocker compose ãããããããããæšå¥šãšã®ããšã
docker compose up -d
http://localhost:3000ã«ã¢ã¯ã»ã¹ããŠã¿ãŸãããã
ãã¿ã³ãæŒããã³ã«ãå°ç²ãªãžã§ãŒã¯ãå±éãããã¯ãã§ãã
ã¡ãªã¿ã«ãDockerfileã倿Žããå Žåã以äžã®ã³ãã³ãã§ã€ã¡ãŒãžãåãã«ãããå¿ èŠããããŸã
docker compose build
ãããã¯ã以äžã®ã³ãã³ãã§ã€ã¡ãŒãžãåãã«ãããŠã³ã³ãããåèµ·åããŸãïŒ
docker compose up -d --build
æåŸã«ãã³ã³ããã忢ããŠãããŸãããã
docker compose down
以äžã§ãã®èšäºã¯çµäºã§ãã
æåŸãŸã§ãèªã¿ããã ãããããšãããããŸãã
Discussion
docker-composeã³ãã³ãã¯ãå€ãæ¹æ³ã§ãdocker composeãäœ¿ãæ¹æ³ãã°ã°ã£ãŠã¿ãŠãã ããdocker-compose.ymlã¯
ããŸã¯compose.ymlãæšå¥šãããŠãŠ
versionããŒã¯å¿ èŠãããŸãããææããããšãããããŸãã
ãã¡ãã«ãã®ããšã«ã€ããŠãæžãããŠãŸããã