-
Notifications
You must be signed in to change notification settings - Fork 8.1k
Open
Labels
area/guideskind/proposalProposal for new content on docs.docker.comProposal for new content on docs.docker.com
Description
Description
คู่มือแปลง Trantech VM เป็น Docker Container
สารบัญ
- ภาพรวมระบบ
- เตรียมความพร้อม
- Backup ข้อมูล
- สร้าง Docker Images
- Docker Compose Setup
- Testing
- Deployment
- Monitoring
- Rollback Plan
ภาพรวมระบบ
ระบบปัจจุบัน (VM-based)
Server 1 (10.2.1.83) - Admin Portal
├── Node.js API (Port 8081) - /root/trantech-api
├── Angular Frontend (Port 3000) - /root/trantech-web
└── Nginx Reverse Proxy (Port 81)
Server 2 (10.2.1.82) - Customer Portal
├── Node.js API (Port 81) - /root/trantech-customer-api
├── Angular Frontend - /root/trantech-customer-web
└── Nginx Reverse Proxy (Port 80)
Server 3 (10.2.1.177) - Document Server
└── Upload API (Port 80)
Server 4 (10.2.1.100) - Database
└── MySQL (Port 3306)
ระบบใหม่ (Docker-based)
Docker Host
├── trantech-admin-api (Container)
├── trantech-admin-web (Container)
├── trantech-customer-api (Container)
├── trantech-customer-web (Container)
├── trantech-document-api (Container)
├── nginx-proxy (Container)
└── mysql (Container - Optional)
เตรียมความพร้อม
1. ติดตั้ง Docker
# ติดตั้ง Docker Engine
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
# ติดตั้ง Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
# เช็คเวอร์ชัน
docker --version
docker-compose --version
# Start Docker service
sudo systemctl start docker
sudo systemctl enable docker2. สร้าง Working Directory
# สร้าง directory structure
mkdir -p /opt/trantech-docker/{admin-api,admin-web,customer-api,customer-web,document-api,nginx,mysql}
cd /opt/trantech-dockerBackup ข้อมูล
1. Backup Database
# สร้าง backup directory
mkdir -p /backup/trantech/$(date +%Y%m%d)
# Backup MySQL database
mysqldump -h 10.2.1.100 -u root -p trantech > /backup/trantech/$(date +%Y%m%d)/trantech_db.sql
# Compress backup
gzip /backup/trantech/$(date +%Y%m%d)/trantech_db.sql2. Backup Application Code
# Admin API & Web
ssh 10.2.1.83 "tar czf /tmp/admin-backup.tar.gz /root/trantech-api /root/trantech-web"
scp 10.2.1.83:/tmp/admin-backup.tar.gz /backup/trantech/$(date +%Y%m%d)/
# Customer API & Web
ssh 10.2.1.82 "tar czf /tmp/customer-backup.tar.gz /root/trantech-customer-api /root/trantech-customer-web"
scp 10.2.1.82:/tmp/customer-backup.tar.gz /backup/trantech/$(date +%Y%m%d)/
# Document API
ssh 10.2.1.177 "tar czf /tmp/document-backup.tar.gz /root/trantech-document-management"
scp 10.2.1.177:/tmp/document-backup.tar.gz /backup/trantech/$(date +%Y%m%d)/3. Backup Nginx Configs
# Backup nginx configs
ssh 10.2.1.83 "tar czf /tmp/nginx-admin.tar.gz /etc/nginx"
scp 10.2.1.83:/tmp/nginx-admin.tar.gz /backup/trantech/$(date +%Y%m%d)/
ssh 10.2.1.82 "tar czf /tmp/nginx-customer.tar.gz /etc/nginx"
scp 10.2.1.82:/tmp/nginx-customer.tar.gz /backup/trantech/$(date +%Y%m%d)/4. Backup PM2 Configs
# Backup PM2 ecosystem files
ssh 10.2.1.83 "pm2 save"
scp 10.2.1.83:/root/.pm2/dump.pm2 /backup/trantech/$(date +%Y%m%d)/admin-pm2.json
ssh 10.2.1.82 "pm2 save"
scp 10.2.1.82:/root/.pm2/dump.pm2 /backup/trantech/$(date +%Y%m%d)/customer-pm2.jsonสร้าง Docker Images
1. Customer API Dockerfile
cat > /opt/trantech-docker/customer-api/Dockerfile << 'EOF'
FROM node:14-alpine
# Set working directory
WORKDIR /app
# Install dependencies first (for better caching)
COPY package*.json ./
RUN npm install --legacy-peer-deps --production
# Copy source code
COPY . .
# Build TypeScript
RUN npm run build
# Create uploads directory
RUN mkdir -p /app/uploads
# Expose port
EXPOSE 3000
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=40s \
CMD node -e "require('http').get('http://localhost:3000/', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"
# Start application
CMD ["node", "app/app.js"]
EOF2. Admin API Dockerfile
cat > /opt/trantech-docker/admin-api/Dockerfile << 'EOF'
FROM node:14-alpine
WORKDIR /app
# Copy package files
COPY package*.json ./
# Install dependencies
RUN npm install --production
# Copy source code
COPY . .
# Expose port
EXPOSE 8081
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=40s \
CMD node -e "require('http').get('http://localhost:8081/', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"
# Start application
CMD ["node", "app.js"]
EOF3. Customer Web Dockerfile
cat > /opt/trantech-docker/customer-web/Dockerfile << 'EOF'
FROM node:14-alpine AS builder
WORKDIR /app
# Copy package files
COPY package*.json ./
# Install dependencies
RUN npm install --legacy-peer-deps
# Copy source code
COPY . .
# Build Angular app
RUN npm run build-prod
# Production stage
FROM nginx:alpine
# Copy built app
COPY --from=builder /app/dist /usr/share/nginx/html
# Copy nginx config
COPY nginx.conf /etc/nginx/conf.d/default.conf
# Expose port
EXPOSE 80
# Health check
HEALTHCHECK --interval=30s --timeout=3s \
CMD wget --quiet --tries=1 --spider http://localhost/ || exit 1
# Start nginx
CMD ["nginx", "-g", "daemon off;"]
EOF4. Nginx Config สำหรับ Customer Web
cat > /opt/trantech-docker/customer-web/nginx.conf << 'EOF'
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
# Gzip compression
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/json;
# Angular routes
location / {
try_files $uri $uri/ /index.html;
}
# Cache static assets
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
EOF5. Document API Dockerfile
cat > /opt/trantech-docker/document-api/Dockerfile << 'EOF'
FROM node:14-alpine
WORKDIR /app
# Copy package files
COPY package*.json ./
# Install dependencies
RUN npm install --production
# Copy source code
COPY . .
# Create uploads directory
RUN mkdir -p /app/uploaded
# Expose port
EXPOSE 80
# Health check
HEALTHCHECK --interval=30s --timeout=3s \
CMD wget --quiet --tries=1 --spider http://localhost/ || exit 1
# Start application
CMD ["node", "server.js"]
EOFDocker Compose Setup
1. สร้าง docker-compose.yml
cat > /opt/trantech-docker/docker-compose.yml << 'EOF'
version: '3.8'
services:
# MySQL Database
mysql:
image: mysql:5.7
container_name: trantech-mysql
environment:
MYSQL_ROOT_PASSWORD: your_root_password
MYSQL_DATABASE: trantech
MYSQL_USER: trantech_user
MYSQL_PASSWORD: your_password
volumes:
- mysql-data:/var/lib/mysql
- ./mysql/init.sql:/docker-entrypoint-initdb.d/init.sql
ports:
- "3306:3306"
networks:
- trantech-network
restart: unless-stopped
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
# Customer API
customer-api:
build: ./customer-api
container_name: trantech-customer-api
environment:
- NODE_ENV=production
- DB_HOST=mysql
- DB_PORT=3306
- DB_NAME=trantech
- DB_USER=trantech_user
- DB_PASSWORD=your_password
- JWT_SECRET=your_jwt_secret
- PORT=3000
ports:
- "3001:3000"
volumes:
- customer-uploads:/app/uploads
depends_on:
mysql:
condition: service_healthy
networks:
- trantech-network
restart: unless-stopped
healthcheck:
test: ["CMD", "node", "-e", "require('http').get('http://localhost:3000/', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
# Customer Web
customer-web:
build: ./customer-web
container_name: trantech-customer-web
ports:
- "3002:80"
depends_on:
- customer-api
networks:
- trantech-network
restart: unless-stopped
# Admin API
admin-api:
build: ./admin-api
container_name: trantech-admin-api
environment:
- NODE_ENV=production
- DB_HOST=mysql
- DB_PORT=3306
- DB_NAME=trantech
- DB_USER=trantech_user
- DB_PASSWORD=your_password
- JWT_SECRET=your_jwt_secret
- PORT=8081
ports:
- "8081:8081"
depends_on:
mysql:
condition: service_healthy
networks:
- trantech-network
restart: unless-stopped
# Admin Web
admin-web:
build: ./admin-web
container_name: trantech-admin-web
ports:
- "3003:80"
depends_on:
- admin-api
networks:
- trantech-network
restart: unless-stopped
# Document API
document-api:
build: ./document-api
container_name: trantech-document-api
ports:
- "3004:80"
volumes:
- document-uploads:/app/uploaded
networks:
- trantech-network
restart: unless-stopped
# Nginx Reverse Proxy
nginx:
image: nginx:alpine
container_name: trantech-nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/conf.d:/etc/nginx/conf.d:ro
- ./nginx/ssl:/etc/nginx/ssl:ro
- ./nginx/logs:/var/log/nginx
depends_on:
- customer-api
- customer-web
- admin-api
- admin-web
- document-api
networks:
- trantech-network
restart: unless-stopped
healthcheck:
test: ["CMD", "nginx", "-t"]
interval: 30s
timeout: 10s
retries: 3
volumes:
mysql-data:
driver: local
customer-uploads:
driver: local
document-uploads:
driver: local
networks:
trantech-network:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/16
EOF2. สร้าง Nginx Reverse Proxy Config
mkdir -p /opt/trantech-docker/nginx/conf.d
cat > /opt/trantech-docker/nginx/conf.d/trantech.conf << 'EOF'
# Customer Portal
server {
listen 80;
server_name customer.trantech.co.th;
# Frontend
location / {
proxy_pass http://customer-web:80;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# API
location /api/ {
proxy_pass http://customer-api:3000/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# CORS
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type' always;
if ($request_method = 'OPTIONS') {
return 204;
}
}
}
# Admin Portal
server {
listen 80;
server_name admin.trantech.co.th;
# Frontend
location / {
proxy_pass http://admin-web:80;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# API
location /api/ {
proxy_pass http://admin-api:8081/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Upload form
location /upload-delivery.html {
proxy_pass http://document-api:80/upload-delivery.html;
proxy_set_header Host $host;
}
}
# API Customer (subdomain)
server {
listen 80;
server_name api-customer.trantech.co.th;
location / {
proxy_pass http://customer-api:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
# Document Upload API
server {
listen 80;
server_name docs.trantech.co.th;
location / {
proxy_pass http://document-api:80;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# File upload settings
client_max_body_size 100M;
proxy_read_timeout 300s;
proxy_connect_timeout 75s;
}
}
EOF3. Environment Variables
cat > /opt/trantech-docker/.env << 'EOF'
# MySQL
MYSQL_ROOT_PASSWORD=your_strong_root_password
MYSQL_DATABASE=trantech
MYSQL_USER=trantech_user
MYSQL_PASSWORD=your_strong_password
# JWT
JWT_SECRET=your_very_secret_jwt_key_change_this
# Node Environment
NODE_ENV=production
# Ports
CUSTOMER_API_PORT=3001
CUSTOMER_WEB_PORT=3002
ADMIN_API_PORT=8081
ADMIN_WEB_PORT=3003
DOCUMENT_API_PORT=3004
NGINX_HTTP_PORT=80
NGINX_HTTPS_PORT=443
EOF
# ตั้งค่า permissions
chmod 600 /opt/trantech-docker/.envCopy Code จาก VM
1. Copy Customer API
# สร้าง directory
mkdir -p /opt/trantech-docker/customer-api
# Copy จาก VM
scp -r 10.2.1.82:/root/trantech-customer-api/* /opt/trantech-docker/customer-api/
# Copy Dockerfile ที่สร้างไว้
cp /opt/trantech-docker/customer-api/Dockerfile /opt/trantech-docker/customer-api/2. Copy Customer Web
mkdir -p /opt/trantech-docker/customer-web
scp -r 10.2.1.82:/root/trantech-customer-web/* /opt/trantech-docker/customer-web/3. Copy Admin API
mkdir -p /opt/trantech-docker/admin-api
scp -r 10.2.1.83:/root/trantech-api/* /opt/trantech-docker/admin-api/4. Copy Admin Web
mkdir -p /opt/trantech-docker/admin-web
scp -r 10.2.1.83:/root/trantech-web/* /opt/trantech-docker/admin-web/5. Copy Document API
mkdir -p /opt/trantech-docker/document-api
scp -r 10.2.1.177:/root/trantech-document-management/* /opt/trantech-docker/document-api/Testing
1. Build Images
cd /opt/trantech-docker
# Build แต่ละ service
docker-compose build customer-api
docker-compose build customer-web
docker-compose build admin-api
docker-compose build admin-web
docker-compose build document-api
# หรือ build ทั้งหมดพร้อมกัน
docker-compose build2. Import Database
# Start MySQL container
docker-compose up -d mysql
# รอให้ MySQL พร้อม
sleep 30
# Import database
docker exec -i trantech-mysql mysql -uroot -pyour_root_password trantech < /backup/trantech/$(date +%Y%m%d)/trantech_db.sql3. Start Services
# Start ทีละ service เพื่อ debug
docker-compose up -d customer-api
docker-compose logs -f customer-api
# ถ้าทำงานได้ start ต่อ
docker-compose up -d customer-web
docker-compose up -d admin-api
docker-compose up -d admin-web
docker-compose up -d document-api
docker-compose up -d nginx4. Health Check
# เช็ค containers ทั้งหมด
docker-compose ps
# เช็ค logs
docker-compose logs --tail=50 -f
# Test endpoints
curl http://localhost:3001/ # Customer API
curl http://localhost:8081/ # Admin API
curl http://localhost:3004/ # Document API
# Test ผ่าน Nginx
curl -H "Host: customer.trantech.co.th" http://localhost/
curl -H "Host: admin.trantech.co.th" http://localhost/5. Test Login
# Test Customer Login
curl -X POST http://localhost:3001/login \
-H "Content-Type: application/json" \
-d '{"username":"testtong","password":"Ridersky128"}'
# Test Admin Login
curl -X POST http://localhost:8081/login/check \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"Ridersky128"}'Deployment
1. Stop VM Services
# หยุด PM2 บน Admin Server
ssh 10.2.1.83 "pm2 stop all"
# หยุด PM2 บน Customer Server
ssh 10.2.1.82 "pm2 stop all"
# หยุด Document Server
ssh 10.2.1.177 "pm2 stop all"2. Update DNS/Load Balancer
# อัพเดท DNS records ชี้ไปที่ Docker host
# หรือ configure load balancer
# ตัวอย่าง: ถ้าใช้ /etc/hosts
cat >> /etc/hosts << EOF
<docker-host-ip> customer.trantech.co.th
<docker-host-ip> admin.trantech.co.th
<docker-host-ip> api-customer.trantech.co.th
<docker-host-ip> docs.trantech.co.th
EOF3. Start Production
cd /opt/trantech-docker
# Start ทุก services
docker-compose up -d
# Monitor logs
docker-compose logs -f4. Verify Production
# เช็ค health
docker-compose ps
# Test URLs
curl https://customer.trantech.co.th/
curl https://admin.trantech.co.th/
curl https://api-customer.trantech.co.th/
# Monitor
watch docker statsMonitoring
1. Container Monitoring
# ดู container stats
docker stats
# ดู logs แบบ real-time
docker-compose logs -f --tail=100
# ดู logs ของ service เฉพาะ
docker-compose logs -f customer-api
# ดู resource usage
docker system df2. Setup Log Rotation
cat > /etc/docker/daemon.json << 'EOF'
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
EOF
# Restart Docker
systemctl restart docker3. Backup Script
cat > /opt/trantech-docker/backup.sh << 'EOF'
#!/bin/bash
BACKUP_DIR="/backup/docker/$(date +%Y%m%d_%H%M%S)"
mkdir -p $BACKUP_DIR
# Backup database
docker exec trantech-mysql mysqldump -uroot -pyour_root_password trantech > $BACKUP_DIR/database.sql
# Backup volumes
docker run --rm -v trantech-docker_mysql-data:/data -v $BACKUP_DIR:/backup alpine tar czf /backup/mysql-data.tar.gz -C /data .
docker run --rm -v trantech-docker_customer-uploads:/data -v $BACKUP_DIR:/backup alpine tar czf /backup/customer-uploads.tar.gz -C /data .
docker run --rm -v trantech-docker_document-uploads:/data -v $BACKUP_DIR:/backup alpine tar czf /backup/document-uploads.tar.gz -C /data .
# Backup docker-compose config
cp /opt/trantech-docker/docker-compose.yml $BACKUP_DIR/
cp /opt/trantech-docker/.env $BACKUP_DIR/
echo "Backup completed: $BACKUP_DIR"
EOF
chmod +x /opt/trantech-docker/backup.sh
# เพิ่ม cronjob
crontab -e
# เพิ่มบรรทัด: 0 2 * * * /opt/trantech-docker/backup.shRollback Plan
1. Quick Rollback Script
cat > /opt/trantech-docker/rollback.sh << 'EOF'
#!/bin/bash
echo "Starting rollback..."
# Stop Docker containers
cd /opt/trantech-docker
docker-compose down
# Start VM services
ssh 10.2.1.83 "pm2 start all"
ssh 10.2.1.82 "pm2 start all"
ssh 10.2.1.177 "pm2 start all"
# Restore DNS (if needed)
# ... add your DNS restore commands
echo "Rollback completed!"
EOF
chmod +x /opt/trantech-docker/rollback.sh2. Restore from Backup
# Restore database
docker exec -i trantech-mysql mysql -uroot -pyour_root_password trantech < /backup/docker/20241231/database.sql
# Restore volumes
docker run --rm -v trantech-docker_mysql-data:/data -v /backup/docker/20241231:/backup alpine tar xzf /backup/mysql-data.tar.gz -C /dataMaintenance Commands
Update Containers
# Pull latest images
docker-compose pull
# Rebuild and restart
docker-compose up -d --build
# Remove old images
docker image prune -aScale Services
# Scale customer API to 3 instances
docker-compose up -d --scale customer-api=3
# Update nginx to load balanceCleanup
# Stop all containers
docker-compose down
# Remove everything including volumes
docker-compose down -v
# Clean up system
docker system prune -a --volumesTroubleshooting
Container ไม่ขึ้น
# ดู logs
docker-compose logs service-name
# เข้าไปใน container
docker exec -it container-name sh
# เช็ค network
docker network ls
docker network inspect trantech-docker_trantech-networkDatabase Connection Error
# เช็คว่า MySQL พร้อมหรือยัง
docker exec trantech-mysql mysqladmin ping -h localhost
# เช็ค connection จาก API container
docker exec customer-api ping mysqlPort Conflict
# เช็คว่า port ถูกใช้อยู่หรือไม่
netstat -tulpn | grep :80
netstat -tulpn | grep :3306
# แก้ไขใน docker-compose.ymlPerformance Tuning
1. Nginx Optimization
# เพิ่มใน nginx.conf
worker_processes auto;
worker_connections 1024;
# Enable caching
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m;2. MySQL Optimization
# เพิ่มใน docker-compose.yml mysql service
command:
- --max-connections=200
- --innodb-buffer-pool-size=512M
- --query-cache-size=32M3. Node.js Optimization
# เพิ่ม environment variables
NODE_OPTIONS=--max-old-space-size=2048
UV_THREADPOOL_SIZE=128Security Checklist
- เปลี่ยน default passwords ทั้งหมด
- ตั้งค่า firewall
- Enable SSL/TLS certificates
- Limit container resources
- Enable Docker security scanning
- Regular security updates
- Backup encryption
- Access control lists
Support & Resources
- Docker Documentation: https://docs.docker.com/
- Docker Compose Documentation: https://docs.docker.com/compose/
- Nginx Documentation: https://nginx.org/en/docs/
- Node.js Best Practices: https://github.com/goldbergyoni/nodebestpractices
หมายเหตุ:
- ทดสอบบน staging environment ก่อน deploy production
- สร้าง backup ก่อนทำการ migration ทุกครั้ง
- เตรียม rollback plan ไว้พร้อมใช้งาน
- Monitor system อย่างใกล้ชิดหลัง deployment
สร้างโดย: Poramet Ek-un
วันที่: 31 ธันวาคม 2025
เวอร์ชัน: 1.0
Would you like to contribute this guide?
- Yes
Metadata
Metadata
Assignees
Labels
area/guideskind/proposalProposal for new content on docs.docker.comProposal for new content on docs.docker.com