🏪 Mở Chi Nhánh - Deployment
Khi nhà hàng đã hoạt động tốt, đã đến lúc mở chi nhánh để phục vụ nhiều khách hàng hơn! Deployment trong Go giống như việc mở các chi nhánh mới - bạn cần đóng gói món ăn (build), chuẩn bị hệ thống giao hàng (cloud), và tự động hóa quy trình sản xuất (CI/CD).
1. Chuẩn Bị Món Ăn - Building Go Binary
Trước khi mở chi nhánh, bạn cần đóng gói món ăn của mình thành sản phẩm hoàn chỉnh.
Build cho hệ điều hành hiện tại
// main.go - Món ăn chính của nhà hàng
package main
import (
"fmt"
"log"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "🍜 Chào mừng đến nhà hàng Code!")
})
log.Println("🏪 Chi nhánh đang mở cửa tại :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
# Đóng gói món ăn (build binary)
go build -o restaurant-app main.go
# Chạy ứng dụng
./restaurant-app
Build cho nhiều nền tảng khác nhau
# Build cho Linux (chi nhánh Linux)
GOOS=linux GOARCH=amd64 go build -o restaurant-linux main.go
# Build cho Windows (chi nhánh Windows)
GOOS=windows GOARCH=amd64 go build -o restaurant-windows.exe main.go
# Build cho macOS (chi nhánh macOS)
GOOS=darwin GOARCH=amd64 go build -o restaurant-macos main.go
# Build nhỏ gọn hơn (giảm kích thước hộp đóng gói)
go build -ldflags="-s -w" -o restaurant-app main.go
2. Hộp Đóng Gói Món Ăn - Docker
Docker giống như hộp đóng gói món ăn chuyên nghiệp - giữ cho món ăn luôn tươi ngon và đồng nhất ở mọi chi nhánh.
Dockerfile cơ bản
# Dockerfile - Công thức đóng gói món ăn
# Giai đoạn 1: Bếp chuẩn bị (Build stage)
FROM golang:1.21-alpine AS builder
# Thiết lập bếp
WORKDIR /kitchen
# Sao chép danh sách nguyên liệu
COPY go.mod go.sum ./
RUN go mod download
# Sao chép nguyên liệu và nấu món
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o restaurant-app .
# Giai đoạn 2: Hộp giao hàng (Runtime stage)
FROM alpine:latest
# Cài đặt công cụ cần thiết
RUN apk --no-cache add ca-certificates
WORKDIR /root/
# Lấy món ăn đã nấu từ bếp
COPY --from=builder /kitchen/restaurant-app .
# Mở cửa cho khách hàng
EXPOSE 8080
# Khởi động nhà hàng
CMD ["./restaurant-app"]
Docker Compose - Quản lý nhiều dịch vụ
# docker-compose.yml - Thiết kế cả hệ thống nhà hàng
version: '3.8'
services:
# Nhà hàng chính
restaurant:
build: .
ports:
- "8080:8080"
environment:
- DB_HOST=database
- REDIS_HOST=cache
depends_on:
- database
- cache
networks:
- restaurant-network
# Kho lưu trữ (Database)
database:
image: postgres:15-alpine
environment:
- POSTGRES_DB=restaurant_db
- POSTGRES_USER=chef
- POSTGRES_PASSWORD=secret123
volumes:
- db-data:/var/lib/postgresql/data
networks:
- restaurant-network
# Tủ lạnh (Cache)
cache:
image: redis:7-alpine
networks:
- restaurant-network
volumes:
db-data:
networks:
restaurant-network:
driver: bridge
Lệnh Docker thường dùng
# Đóng gói món ăn vào hộp
docker build -t restaurant-app:v1.0 .
# Chạy thử hộp đóng gói
docker run -p 8080:8080 restaurant-app:v1.0
# Chạy cả hệ thống
docker-compose up -d
# Kiểm tra tình trạng các dịch vụ
docker-compose ps
# Xem log của nhà hàng
docker-compose logs -f restaurant
# Dừng hệ thống
docker-compose down
3. Hệ Thống Giao Hàng - Cloud Deployment
Sau khi đóng gói, bạn cần chọn hệ thống giao hàng (cloud platform) phù hợp.
Heroku - Giao hàng đơn giản
# Cài đặt Heroku CLI
# Tạo file Procfile
echo "web: ./restaurant-app" > Procfile
# Đăng nhập và tạo ứng dụng
heroku login
heroku create my-restaurant-app
# Triển khai
git push heroku main
# Xem log
heroku logs --tail
# Mở ứng dụng
heroku open
AWS Elastic Beanstalk
# Cài đặt EB CLI
pip install awsebcli
# Khởi tạo môi trường
eb init -p go restaurant-app
# Tạo môi trường
eb create restaurant-prod
# Triển khai
eb deploy
# Mở ứng dụng
eb open
# Xem trạng thái
eb status
Google Cloud Platform (GCP)
# Tạo file app.yaml
cat > app.yaml << EOF
runtime: go121
main: .
env_variables:
PORT: "8080"
EOF
# Triển khai lên App Engine
gcloud app deploy
# Xem ứng dụng
gcloud app browse
# Xem log
gcloud app logs tail -s default
4. Kubernetes - Hệ Thống Chi Nhánh Lớn
Kubernetes giống như quản lý chuỗi nhà hàng lớn với nhiều chi nhánh.
Deployment YAML
# deployment.yaml - Kế hoạch mở chi nhánh
apiVersion: apps/v1
kind: Deployment
metadata:
name: restaurant-deployment
spec:
replicas: 3 # Mở 3 chi nhánh
selector:
matchLabels:
app: restaurant
template:
metadata:
labels:
app: restaurant
spec:
containers:
- name: restaurant-app
image: restaurant-app:v1.0
ports:
- containerPort: 8080
env:
- name: DB_HOST
value: "postgres-service"
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
name: restaurant-service
spec:
selector:
app: restaurant
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: LoadBalancer
# Triển khai lên Kubernetes
kubectl apply -f deployment.yaml
# Kiểm tra pods (các chi nhánh)
kubectl get pods
# Kiểm tra service
kubectl get services
# Xem log của một chi nhánh
kubectl logs <pod-name>
# Scale lên 5 chi nhánh
kubectl scale deployment restaurant-deployment --replicas=5
5. Dây Chuyền Tự Động - CI/CD
CI/CD giống như dây chuyền sản xuất tự động - tự động kiểm tra, đóng gói và giao hàng.
GitHub Actions
# .github/workflows/deploy.yml - Quy trình tự động hóa
name: 🏪 Mở Chi Nhánh Tự Động
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
# Kiểm tra chất lượng món ăn
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Go
uses: actions/setup-go@v4
with:
go-version: '1.21'
- name: Chạy tests
run: |
go test -v ./...
go test -race -coverprofile=coverage.txt -covermode=atomic ./...
- name: Kiểm tra chất lượng code
run: |
go vet ./...
go fmt ./...
# Đóng gói và triển khai
deploy:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v3
- name: Đăng nhập Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build và push Docker image
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: |
myusername/restaurant-app:latest
myusername/restaurant-app:${{ github.sha }}
- name: Triển khai lên production
run: |
# Triển khai lên cloud platform của bạn
echo "🚀 Đang mở chi nhánh mới..."
GitLab CI/CD
# .gitlab-ci.yml
stages:
- test
- build
- deploy
variables:
DOCKER_IMAGE: registry.gitlab.com/mygroup/restaurant-app
# Kiểm tra món ăn
test:
stage: test
image: golang:1.21
script:
- go test -v ./...
- go vet ./...
# Đóng gói món ăn
build:
stage: build
image: docker:latest
services:
- docker:dind
script:
- docker build -t $DOCKER_IMAGE:$CI_COMMIT_SHA .
- docker push $DOCKER_IMAGE:$CI_COMMIT_SHA
only:
- main
# Mở chi nhánh
deploy:
stage: deploy
script:
- kubectl set image deployment/restaurant-deployment restaurant-app=$DOCKER_IMAGE:$CI_COMMIT_SHA
only:
- main
environment:
name: production
6. Cấu Hình Môi Trường - Environment Variables
Mỗi chi nhánh có thể cần cấu hình khác nhau.
// config/config.go - Cấu hình cho từng chi nhánh
package config
import (
"os"
"strconv"
)
type Config struct {
ServerPort string
DatabaseURL string
RedisURL string
Environment string
LogLevel string
}
func Load() *Config {
return &Config{
ServerPort: getEnv("PORT", "8080"),
DatabaseURL: getEnv("DATABASE_URL", "postgres://localhost/restaurant"),
RedisURL: getEnv("REDIS_URL", "localhost:6379"),
Environment: getEnv("ENV", "development"),
LogLevel: getEnv("LOG_LEVEL", "info"),
}
}
func getEnv(key, defaultValue string) string {
if value := os.Getenv(key); value != "" {
return value
}
return defaultValue
}
func getEnvAsInt(key string, defaultValue int) int {
if value := os.Getenv(key); value != "" {
if intValue, err := strconv.Atoi(value); err == nil {
return intValue
}
}
return defaultValue
}
File .env cho các môi trường
# .env.development - Chi nhánh thử nghiệm
ENV=development
PORT=8080
DATABASE_URL=postgres://localhost:5432/restaurant_dev
REDIS_URL=localhost:6379
LOG_LEVEL=debug
# .env.production - Chi nhánh chính thức
ENV=production
PORT=8080
DATABASE_URL=postgres://prod-db:5432/restaurant_prod
REDIS_URL=prod-redis:6379
LOG_LEVEL=info
7. Health Checks - Kiểm Tra Sức Khỏe
Đảm bảo chi nhánh luôn hoạt động tốt.
// health/health.go - Kiểm tra sức khỏe nhà hàng
package health
import (
"encoding/json"
"net/http"
"time"
)
type HealthStatus struct {
Status string `json:"status"`
Timestamp time.Time `json:"timestamp"`
Services map[string]string `json:"services"`
}
func HealthCheckHandler(w http.ResponseWriter, r *http.Request) {
status := HealthStatus{
Status: "healthy",
Timestamp: time.Now(),
Services: make(map[string]string),
}
// Kiểm tra database
if checkDatabase() {
status.Services["database"] = "ok"
} else {
status.Services["database"] = "error"
status.Status = "unhealthy"
}
// Kiểm tra cache
if checkRedis() {
status.Services["redis"] = "ok"
} else {
status.Services["redis"] = "error"
status.Status = "degraded"
}
w.Header().Set("Content-Type", "application/json")
if status.Status != "healthy" {
w.WriteHeader(http.StatusServiceUnavailable)
}
json.NewEncoder(w).Encode(status)
}
func ReadinessHandler(w http.ResponseWriter, r *http.Request) {
// Kiểm tra xem service đã sẵn sàng phục vụ chưa
w.WriteHeader(http.StatusOK)
w.Write([]byte("ready"))
}
func checkDatabase() bool {
// Implement database check
return true
}
func checkRedis() bool {
// Implement redis check
return true
}
8. Monitoring và Logging - Giám Sát Chi Nhánh
Theo dõi hoạt động của các chi nhánh.
// logging/logger.go - Hệ thống ghi chép
package logging
import (
"log"
"os"
"time"
"net/http"
)
type Logger struct {
infoLog *log.Logger
errorLog *log.Logger
}
func NewLogger() *Logger {
return &Logger{
infoLog: log.New(os.Stdout, "INFO\t", log.Ldate|log.Ltime),
errorLog: log.New(os.Stderr, "ERROR\t", log.Ldate|log.Ltime|log.Lshortfile),
}
}
func (l *Logger) Info(format string, v ...interface{}) {
l.infoLog.Printf(format, v...)
}
func (l *Logger) Error(format string, v ...interface{}) {
l.errorLog.Printf(format, v...)
}
// Middleware để log requests
func RequestLogger(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
next.ServeHTTP(w, r)
log.Printf(
"🍽️ %s %s %s - Thời gian xử lý: %v",
r.Method,
r.RequestURI,
r.RemoteAddr,
time.Since(start),
)
})
}
Tích hợp với monitoring services
// monitoring/metrics.go
package monitoring
import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"net/http"
)
var (
// Đếm số khách hàng
requestsTotal = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "restaurant_requests_total",
Help: "Tổng số yêu cầu",
},
[]string{"method", "endpoint"},
)
// Thời gian phục vụ
requestDuration = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "restaurant_request_duration_seconds",
Help: "Thời gian xử lý yêu cầu",
},
[]string{"method", "endpoint"},
)
)
func init() {
prometheus.MustRegister(requestsTotal)
prometheus.MustRegister(requestDuration)
}
func MetricsHandler() http.Handler {
return promhttp.Handler()
}
9. Bài Tập Thực Hành
Bài 1: Đóng gói cơ bản
Tạo một Go web server đơn giản và viết Dockerfile để đóng gói nó.
Bài 2: Multi-stage build
Tối ưu hóa Dockerfile để giảm kích thước image xuống dưới 20MB.
Bài 3: Docker Compose
Tạo docker-compose.yml cho ứng dụng có web server, PostgreSQL và Redis.
Bài 4: Health checks
Implement các endpoint /health và /ready cho ứng dụng của bạn.
Bài 5: CI/CD pipeline
Thiết lập GitHub Actions để tự động test và build Docker image.
Bài 6: Kubernetes deployment
Viết deployment.yaml để deploy ứng dụng lên Kubernetes với 3 replicas.
Bài 7: Environment configuration
Tạo hệ thống config hỗ trợ nhiều môi trường (dev, staging, production).
Bài 8: Monitoring
Tích hợp Prometheus metrics vào ứng dụng của bạn.
Tổng Kết
Deployment giống như mở chi nhánh nhà hàng:
- 📦 Build: Đóng gói món ăn
- 🐳 Docker: Hộp đóng gói chuyên nghiệp
- ☁️ Cloud: Hệ thống giao hàng
- 🔄 CI/CD: Dây chuyền tự động
- 📊 Monitoring: Giám sát chi nhánh
- 🏥 Health checks: Kiểm tra sức khỏe
- ⚙️ Config: Tùy chỉnh từng chi nhánh
- 🚀 K8s: Quản lý chuỗi lớn
Việc deployment đúng cách giúp ứng dụng của bạn chạy ổn định và dễ dàng mở rộng!
Tiếp theo: 🛠️ Công Cụ & Best Practices - Tools