I. Docker compose là gì ?
Docker compose là công cụ giúp bạn xác định và chạy nhiều container trong một ứng dụng Docker. Bằng việc sử dụng compose, bạn có thể cấu hình các dịch vụ trong ứng dụng của bạn bằng cách sử dụng tệp YAML và sau đó sử dụng các lệnh để tạo và chạy các container dựa trên cấu hình đó. Việc sử dụng compose khá đơn giản chỉ với ba bước:
- Khai báo môi trường ứng dụng trong Dockerfile.
- Khai báo các dịch vụ cần thiết để chạy ứng dụng trong tệp docker-compose.yml.
- Chạy lệnh docker-compose up để khởi động và chạy ứng dụng.
II. Tính năng chính
Không giống như Dockerfile (dùng để build các image), Docker compose được sử dụng để build và chạy các container. Các thao tác của docker-compose tương tự như lệnh docker run.
Docker compose cho phép tạo nhiều service (container) giống nhau bằng lệnh:
$ docker-compose scale <tên service> = <số lượng>
III. Hướng dẫn cài đặt
1. Thiết lập ứng dụng web:
- Sử dụng npm:
npm init react-app <tên app>
- Hoặc sử dụng yarn:
yarn create react-app <tên app>
Trong bài demo này, chúng ta sẽ sử dụng React JS.
- Thay đổi file App.js:
import React, { useState } from 'react';
import './App.css';
function status(response) {
if (response.status >= 200 && response.status < 300) {
return Promise.resolve(response)
} else {
return Promise.reject(new Error(response.statusText))
}
}
function json(response) {
return response.json()
}
const getFoodDetail = (foodId) => {
return fetch(
"http://localhost:8080/api/v1/foods?id=" + foodId,
{
method: "GET",
headers: {
"Content-Type": "application/json; charset=UTF-8"
}
}
)
.then(status)
.then(json)
.then(res => (new Promise((resolve, reject) => resolve(res.data))))
.catch(err => {
alert("err: ", err);
return undefined;
});
};
function App() {
const [foodId, setFoodId] = useState(0);
const [dataFood, setDataFood] = useState("");
return (
<div className="App">
<header className="App-header">
<h3 color="while">App tìm món ăn theo id</h3>
<div>
<input className="input" name="id" placehodler="Nhập id" onChange={(e) => setFoodId(e.target.value)}/>
<button className="btnSearch" onClick={() => { getFoodDetail(foodId).then(data => setDataFood(data)) }}>
Tìm kiếm
</button>
<p style={{textAlign: "left"}}>Kết quả: {dataFood}</p>
</div>
</header>
</div>
);
}
export default App;
- Thay đổi file App.css:
.App {
text-align: center;
}
.App-logo {
animation: App-logo-spin infinite 20s linear;
height: 40vmin;
pointer-events: none;
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.input {
padding: 10px;
width: 200px;
border: 0;
box-shadow: 0px 2px 30px 0px rgba(255,255,15,1);
margin-right: 10px;
}
.btnSearch {
padding: 10px 50px;
color: white;
background: blueviolet;
border: 0;
border-radius: 20px;
}
.btnSearch:hover {
background: #c837de;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
2. Thiết lập server:
- File main.go:
package main
import (
"net/http"
"strconv"
"github.com/gin-gonic/gin"
)
func Options(c *gin.Context) {
if c.Request.Method != "OPTIONS" {
c.Next()
} else {
c.Header("Access-Control-Allow-Origin", "*")
c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS")
c.Header("Access-Control-Allow-Headers", "authorization, origin, content-type, accept")
c.Header("Allow", "HEAD, GET, POST, PUT, PATCH, DELETE, OPTIONS")
c.Header("Content-Type", "application/json")
c.AbortWithStatus(200)
}
}
func Secure(c *gin.Context) {
c.Header("Access-Control-Allow-Origin", "*")
}
type Foods map[int]string
var foods = Foods{
1: "Gà kho xả ớt",
2: "Cá lóc kho",
3: "Thịt xào măng",
4: "Bún chả cá",
}
func getFoodById(c *gin.Context) {
id, err := strconv.Atoi(c.Query("id"))
if err != nil {
c.JSON(http.StatusOK, gin.H{"error": err.Error()})
}
if len(foods[id]) > 0 {
c.JSON(http.StatusOK, gin.H{"data": foods[id]})
} else {
c.JSON(http.StatusOK, gin.H{"data": "Không tìm thấy"})
}
}
func main() {
r := gin.Default()
r.Use(Options)
r.Use(Secure)
v1 := r.Group("/api/v1")
{
v1.GET("/foods", getFoodById)
}
r.Run(":8080")
}
3. Cấu hình Dockerfile
Nếu bạn không quen thuộc với việc cấu hình Dockerfile, đừng lo lắng! Hãy xem lại phần 1 tại đây để biết thêm thông tin chi tiết.
FROM node:carbon-alpine AS node_builder
WORKDIR /app/webreactjs
COPY /webreactjs/package.json .
RUN npm install
COPY /webreactjs .
LABEL name="webreactjs" version="1.0"
EXPOSE 3000
CMD ["npm", "start"]
FROM golang:1.11 AS go_builder
ADD . /app
WORKDIR /app
RUN go mod download
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-w" -a -o /main .
LABEL name="server" version="1.0"
FROM alpine:latest
RUN apk -no-cache add ca-certificates
COPY --from=go_builder /main ./
RUN chmod +x ./main
EXPOSE 8080
CMD ./main
4. Cấu hình docker-compose.yml
version: '2.1'
services:
webreactjs:
image: af1205224676
build: .
ports:
- 3000:3000
restart: always
servergo:
image: cef5deda0834
build: .
ports:
- 8080:8080
restart: always
Trong file docker-compose.yml, chúng ta thiết lập các dịch vụ (containers) cần cài đặt và chạy.
version
: chỉ ra phiên bản của docker-compose đã sử dụng.services
: thiết lập các dịch vụ (containers) cần cài đặt và chạy.image
: chỉ ra image được sử dụng để tạo container.build
: dùng để tạo container từ Dockerfile.ports
: thiết lập cổng chạy trên máy chủ và trong container.restart
: tự động khởi động lại container khi nó bị tắt.
Ngoài ra, còn có một số lệnh config khác như environment
để thiết lập biến môi trường, depends_on
để chỉ ra sự phụ thuộc giữa các dịch vụ, và volumes
để mount các thư mục giữa máy chủ và container.
- Chạy lệnh sau để khởi động ứng dụng:
$ docker-compose up
Sau khi chạy xong, bạn sẽ thấy docker-compose đã khởi động và chạy hai dịch vụ mà chúng ta đã cấu hình trong file docker-compose.yml.
Hãy ngắm nhìn thành quả:
- Ứng dụng web được chạy tại: http://localhost:3000
- Server được chạy tại: http://localhost:8080
Mẹo nhỏ
Đối với những bạn sử dụng Visual Studio Code, bạn có thể nhanh chóng tạo các config cho Dockerfile và docker-compose.yml chỉ bằng một vài thao tác đơn giản. Cài đặt extension Docker trên Visual Studio Code và sau đó nhấn F1, gõ “docker: add” và chọn mẫu tạo có sẵn kèm theo cấu hình port. Visual Studio Code sẽ tự động tạo các file Dockerfile, docker-compose.yml, docker-compose.debug.yml và .dockerignore cho bạn. Ngoài ra, extension còn cung cấp gợi ý lệnh và cảnh báo khi bạn tự cấu hình các file Docker, rất tiện lợi.
Đây là bản dịch và chỉnh sửa từ bài viết gốc của dnulib.edu.vn. Để biết thêm chi tiết, hãy truy cập dnulib.edu.vn