Từ code đến production
Spring Boot application có thể deploy bằng nhiều cách. Bài này đi từ đơn giản nhất đến production-ready.
Build JAR file
Spring Boot tạo fat JAR (executable JAR) chứa tất cả dependencies:
# Maven
./mvnw clean package -DskipTests
# Gradle
./gradlew bootJar
# Chạy JAR
java -jar target/myapp-0.0.1-SNAPSHOT.jar
ℹ️ Fat JAR vs Thin JAR
Fat JAR chứa tất cả dependencies (~50-100MB). Ưu điểm: deploy đơn giản, chỉ cần JRE. Nhược điểm: file lớn, build chậm.
Spring Profiles
Tách config theo môi trường:
# application.yml — config chung
spring:
application:
name: myapp
# application-dev.yml — chỉ cho development
server:
port: 8080
spring:
datasource:
url: jdbc:h2:mem:devdb
# application-prod.yml — chỉ cho production
server:
port: 80
spring:
datasource:
url: jdbc:postgresql://db:5432/myapp
Kích hoạt profile:
# Qua command line
java -jar myapp.jar --spring.profiles.active=prod
# Qua biến môi trường
SPRING_PROFILES_ACTIVE=prod java -jar myapp.jar
Docker hóa Spring Boot
# Multi-stage build
FROM eclipse-temurin:21-jdk-alpine AS build
WORKDIR /app
COPY . .
RUN ./mvnw clean package -DskipTests
FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
COPY --from=build /app/target/*.jar app.jar
# Non-root user
RUN addgroup -S spring && adduser -S spring -G spring
USER spring
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
docker build -t myapp .
docker run -p 8080:8080 -e SPRING_PROFILES_ACTIVE=prod myapp
Health Check với Actuator
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
# application.yml
management:
endpoints:
web:
exposure:
include: health,info,metrics
endpoint:
health:
show-details: when_authorized
Truy cập http://localhost:8080/actuator/health:
{
"status": "UP",
"components": {
"db": { "status": "UP" },
"diskSpace": { "status": "UP" }
}
}
Externalized Configuration
Thứ tự ưu tiên config (cao → thấp):
- Command line arguments (
--server.port=9090) - Environment variables (
SERVER_PORT=9090) application-{profile}.ymlapplication.yml- Default values trong code
@Configuration
public class AppConfig {
@Value("${app.upload.max-size:10MB}") // default 10MB
private String maxUploadSize;
@Value("${app.feature.ai-explain:false}")
private boolean aiExplainEnabled;
}
⚠️ Không hardcode secrets!
Database password, API key KHÔNG BAO GIỜ đặt trong application.yml. Dùng environment variables hoặc secret manager (Vault, AWS Secrets Manager).
Checklist deploy production
- Build JAR/Docker image thành công
- Profile
prodđã cấu hình đúng - Health check endpoint hoạt động
- Secrets được inject qua env vars
- Logging level phù hợp (INFO cho prod)
- CORS, Security headers đã cấu hình
- Database migration đã chạy