← Назад к вопросам
Как конфигурируется различное окружение для каждого стенда
2.0 Middle🔥 201 комментариев
#Docker, Kubernetes и DevOps
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как конфигурируется различное окружение для каждого стенда
Управление конфигурацией для разных сред (dev, staging, prod) — критическая задача в Spring Boot приложениях. Существует несколько стандартных подходов.
1. Spring Profiles — основной механизм
Это встроенное решение Spring для управления конфигурацией по окружению:
# application.yml (базовая конфигурация)
spring:
application:
name: my-app
jpa:
hibernate:
ddl-auto: validate
app:
feature-flags:
analytics-enabled: true
# application-dev.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/myapp_dev
username: dev
password: dev123
jpa:
show-sql: true
properties:
hibernate.format_sql: true
app:
debug: true
log-level: DEBUG
# application-staging.yml
spring:
datasource:
url: jdbc:mysql://staging-db.internal:3306/myapp_staging
username: ${DB_USER}
password: ${DB_PASSWORD}
jpa:
show-sql: false
app:
debug: false
log-level: INFO
# application-prod.yml
spring:
datasource:
url: jdbc:mysql://${PROD_DB_HOST}:3306/myapp
username: ${PROD_DB_USER}
password: ${PROD_DB_PASSWORD}
jpa:
show-sql: false
properties:
hibernate.generate_statistics: false
app:
debug: false
log-level: WARN
cache-ttl: 3600
2. Активация профилей
# Через системное свойство при запуске
java -jar app.jar --spring.profiles.active=dev
# Через переменную окружения
export SPRING_PROFILES_ACTIVE=staging
java -jar app.jar
# Через application.properties
# application.properties
spring.profiles.active=prod
# Через Docker переменную
DOCKER_OPTS="-e SPRING_PROFILES_ACTIVE=staging"
3. Конфигурация через @Configuration классы
@Configuration
@Profile("dev")
public class DevConfig {
@Bean
public DataSource devDataSource() {
return DataSourceBuilder.create()
.driverClassName("org.h2.Driver")
.url("jdbc:h2:mem:testdb")
.username("sa")
.password("")
.build();
}
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
public EmailService emailService() {
// Mock email service для разработки
return new MockEmailService();
}
}
@Configuration
@Profile("prod")
public class ProdConfig {
@Bean
public DataSource prodDataSource(
@Value("${prod.db.host}") String host,
@Value("${prod.db.port}") int port,
@Value("${prod.db.name}") String database) {
return DataSourceBuilder.create()
.driverClassName("org.postgresql.Driver")
.url("jdbc:postgresql://" + host + ":" + port + "/" + database)
.username(System.getenv("DB_USER"))
.password(System.getenv("DB_PASSWORD"))
.hikari(HikariConfig.withConnectionPoolSize(20))
.build();
}
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder
.setConnectTimeout(Duration.ofSeconds(5))
.setReadTimeout(Duration.ofSeconds(10))
.build();
}
@Bean
public EmailService emailService(EmailProperties properties) {
return new SmtpEmailService(properties);
}
}
4. Управляемые свойства через @ConfigurationProperties
@Configuration
@ConfigurationProperties(prefix = "app")
public class AppProperties {
private Database database = new Database();
private Cache cache = new Cache();
private Security security = new Security();
private String environment;
public static class Database {
private String host;
private int port;
private String name;
private int maxConnections;
// getters/setters
}
public static class Cache {
private long ttl;
private boolean enabled;
private String implementation; // redis, memcached, local
// getters/setters
}
public static class Security {
private String jwtSecret;
private long jwtExpiration;
private List<String> allowedOrigins;
// getters/setters
}
}
// Использование
@Service
public class AuthService {
private final AppProperties appProperties;
public AuthService(AppProperties appProperties) {
this.appProperties = appProperties;
}
public String createToken(User user) {
return Jwts.builder()
.subject(user.getId().toString())
.issuedAt(new Date())
.expiration(new Date(System.currentTimeMillis() +
appProperties.getSecurity().getJwtExpiration()))
.signWith(Keys.hmacShaKeyFor(
appProperties.getSecurity().getJwtSecret().getBytes()))
.compact();
}
}
5. YAML структура для разных сред
# application.yml
spring:
config:
import:
- optional:file:./config/application-${spring.profiles.active}.yml
application:
name: my-app
profiles:
active: dev
include:
- common
- features
📁 resources/
├── application.yml
├── application-common.yml (общие свойства)
├── application-dev.yml
├── application-staging.yml
├── application-prod.yml
├── application-features.yml (feature flags)
└── logback-spring.xml (различные уровни логирования)
6. Environment переменные и Secrets
@Service
public class EnvironmentService {
private final Environment env;
public EnvironmentService(Environment env) {
this.env = env;
}
public String getDatabaseUrl() {
// Приоритет: системное свойство → переменная окружения → default
return env.getProperty(
"spring.datasource.url",
"jdbc:mysql://localhost:3306/myapp"
);
}
public String getApiKey() {
// Для production secrets используй переменные окружения
String key = env.getProperty("API_KEY");
if (key == null && !isProduction()) {
key = "dev-key-12345"; // Fallback только для dev
}
return key;
}
private boolean isProduction() {
return "prod".equals(env.getActiveProfiles());
}
}
7. Conditional beans по профилю
@Configuration
public class ServiceConfig {
@Bean
@ConditionalOnProfile("dev")
public LoggingAspect devLoggingAspect() {
return new VerboseLoggingAspect(); // Логирует всё подряд
}
@Bean
@ConditionalOnProfile("prod")
public LoggingAspect prodLoggingAspect() {
return new MinimalLoggingAspect(); // Логирует только ошибки
}
@Bean
@ConditionalOnProfile({"dev", "staging"})
public MockExternalService mockService() {
return new MockExternalService();
}
@Bean
@ConditionalOnProfile("prod")
public RealExternalService realService(ExternalApiClient client) {
return new RealExternalService(client);
}
}
8. Пример Dockerfile с профилями
# Dockerfile
FROM openjdk:17-slim
ARG SPRING_PROFILE=dev
ENV SPRING_PROFILES_ACTIVE=${SPRING_PROFILE}
COPY target/app.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]
# Использование:
# docker build --build-arg SPRING_PROFILE=prod -t myapp:prod .
# docker run -e SPRING_PROFILES_ACTIVE=staging myapp:prod
9. Docker Compose с разными конфигурациями
version: '3.8'
services:
app-dev:
build:
context: .
args:
SPRING_PROFILE: dev
environment:
- SPRING_PROFILES_ACTIVE=dev
- DATABASE_URL=jdbc:mysql://mysql-dev:3306/myapp
ports:
- "8080:8080"
app-prod:
build:
context: .
args:
SPRING_PROFILE: prod
environment:
- SPRING_PROFILES_ACTIVE=prod
- DATABASE_URL=jdbc:postgresql://postgres-prod:5432/myapp
- DB_USER=${PROD_DB_USER}
- DB_PASSWORD=${PROD_DB_PASSWORD}
ports:
- "8443:8443"
depends_on:
- postgres-prod
mysql-dev:
image: mysql:8
environment:
- MYSQL_DATABASE=myapp
- MYSQL_ROOT_PASSWORD=dev123
10. Kubernetes ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config-prod
data:
application-prod.yml: |
spring:
datasource:
url: jdbc:postgresql://postgres:5432/myapp
username: ${POSTGRES_USER}
password: ${POSTGRES_PASSWORD}
jpa:
show-sql: false
app:
log-level: WARN
cache-ttl: 3600
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
template:
spec:
containers:
- name: app
image: myapp:latest
env:
- name: SPRING_PROFILES_ACTIVE
value: "prod"
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: db-credentials
key: username
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password
volumeMounts:
- name: config
mountPath: /app/config
volumes:
- name: config
configMap:
name: app-config-prod
Итоговая таблица управления конфигурацией
| Механизм | Dev | Staging | Prod | Пример |
|---|---|---|---|---|
| application-*.yml | ✓ | ✓ | ✓ | DB хосты, лог-уровень |
| Переменные окружения | ✓ | ✓ | ✓ | Пароли, API ключи |
| @Profile классы | ✓ | ✓ | ✓ | Mock vs Real сервисы |
| @ConfigurationProperties | ✓ | ✓ | ✓ | Типизированные свойства |
| Secrets (K8s/Docker) | ✗ | ✓ | ✓ | Ключи, пароли БД |
| Консоль при запуске | ✓ | ✗ | ✗ | Переопределение на лету |
Знание этих подходов позволяет строить масштабируемые приложения, которые легко развертываются в разных окружениях.