Skip to content

Commit a3d0b4b

Browse files
committed
feat: 로컬 이미지 업로드를 MinIO로 분리
1 parent 23f15e4 commit a3d0b4b

3 files changed

Lines changed: 102 additions & 8 deletions

File tree

infra/docker-compose.local.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,47 @@ services:
7070
networks:
7171
- docsa_local_net
7272

73+
minio:
74+
image: minio/minio:latest
75+
container_name: docsa-minio-local
76+
restart: unless-stopped
77+
command: ["server", "/data", "--console-address", ":9001"]
78+
environment:
79+
MINIO_ROOT_USER: ${LOCAL_MINIO_ROOT_USER:-docsa-local}
80+
MINIO_ROOT_PASSWORD: ${LOCAL_MINIO_ROOT_PASSWORD:-docsa-local-password}
81+
MINIO_API_CORS_ALLOW_ORIGIN: ${LOCAL_MINIO_CORS_ALLOW_ORIGIN:-http://localhost:3000,http://localhost:5173}
82+
TZ: Asia/Seoul
83+
ports:
84+
- "${LOCAL_MINIO_API_PORT:-9000}:9000"
85+
- "${LOCAL_MINIO_CONSOLE_PORT:-9001}:9001"
86+
volumes:
87+
- local_minio_data:/data
88+
networks:
89+
- docsa_local_net
90+
91+
minio-init:
92+
image: minio/mc:latest
93+
container_name: docsa-minio-init-local
94+
depends_on:
95+
- minio
96+
environment:
97+
LOCAL_MINIO_ROOT_USER: ${LOCAL_MINIO_ROOT_USER:-docsa-local}
98+
LOCAL_MINIO_ROOT_PASSWORD: ${LOCAL_MINIO_ROOT_PASSWORD:-docsa-local-password}
99+
LOCAL_MINIO_BUCKET: ${LOCAL_MINIO_BUCKET:-docsa-local}
100+
entrypoint: >
101+
/bin/sh -c "
102+
until mc alias set local http://minio:9000 ${LOCAL_MINIO_ROOT_USER:-docsa-local} ${LOCAL_MINIO_ROOT_PASSWORD:-docsa-local-password}; do sleep 2; done;
103+
mc mb --ignore-existing local/${LOCAL_MINIO_BUCKET:-docsa-local};
104+
mc anonymous set download local/${LOCAL_MINIO_BUCKET:-docsa-local};
105+
"
106+
networks:
107+
- docsa_local_net
108+
73109
volumes:
74110
local_mysql_data:
75111
local_mongo_data:
76112
local_mailpit_data:
113+
local_minio_data:
77114

78115
networks:
79116
docsa_local_net:
Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
package io.ejangs.docsa.domain.image.config;
22

3+
import java.net.URI;
34
import lombok.RequiredArgsConstructor;
45

56
import org.springframework.beans.factory.annotation.Value;
67
import org.springframework.context.annotation.Bean;
78
import org.springframework.context.annotation.Configuration;
9+
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
10+
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
811
import software.amazon.awssdk.regions.Region;
912
import software.amazon.awssdk.services.s3.S3Client;
13+
import software.amazon.awssdk.services.s3.S3ClientBuilder;
14+
import software.amazon.awssdk.services.s3.S3Configuration;
1015
import software.amazon.awssdk.services.s3.presigner.S3Presigner;
1116

1217
@Configuration
@@ -15,19 +20,59 @@ public class S3Config {
1520

1621
@Bean
1722
public S3Presigner s3Presigner(
18-
@Value("${cloud.aws.region}") String region
23+
@Value("${cloud.aws.region}") String region,
24+
@Value("${cloud.aws.s3.endpoint:}") String endpoint,
25+
@Value("${cloud.aws.s3.path-style-access-enabled:false}") boolean pathStyleAccessEnabled,
26+
@Value("${cloud.aws.credentials.access-key:}") String accessKey,
27+
@Value("${cloud.aws.credentials.secret-key:}") String secretKey
1928
) {
20-
return S3Presigner.builder()
21-
.region(Region.of(region))
22-
.build();
29+
S3Presigner.Builder builder = S3Presigner.builder()
30+
.region(Region.of(region));
31+
32+
if (!endpoint.isBlank()) {
33+
builder.endpointOverride(URI.create(endpoint));
34+
}
35+
36+
if (pathStyleAccessEnabled) {
37+
builder.serviceConfiguration(S3Configuration.builder()
38+
.pathStyleAccessEnabled(true)
39+
.build());
40+
}
41+
42+
if (!accessKey.isBlank() && !secretKey.isBlank()) {
43+
builder.credentialsProvider(StaticCredentialsProvider.create(
44+
AwsBasicCredentials.create(accessKey, secretKey)));
45+
}
46+
47+
return builder.build();
2348
}
2449

2550
@Bean
2651
public S3Client s3Client(
27-
@Value("${cloud.aws.region}") String region
52+
@Value("${cloud.aws.region}") String region,
53+
@Value("${cloud.aws.s3.endpoint:}") String endpoint,
54+
@Value("${cloud.aws.s3.path-style-access-enabled:false}") boolean pathStyleAccessEnabled,
55+
@Value("${cloud.aws.credentials.access-key:}") String accessKey,
56+
@Value("${cloud.aws.credentials.secret-key:}") String secretKey
2857
) {
29-
return S3Client.builder()
30-
.region(Region.of(region))
31-
.build();
58+
S3ClientBuilder builder = S3Client.builder()
59+
.region(Region.of(region));
60+
61+
if (!endpoint.isBlank()) {
62+
builder.endpointOverride(URI.create(endpoint));
63+
}
64+
65+
if (pathStyleAccessEnabled) {
66+
builder.serviceConfiguration(S3Configuration.builder()
67+
.pathStyleAccessEnabled(true)
68+
.build());
69+
}
70+
71+
if (!accessKey.isBlank() && !secretKey.isBlank()) {
72+
builder.credentialsProvider(StaticCredentialsProvider.create(
73+
AwsBasicCredentials.create(accessKey, secretKey)));
74+
}
75+
76+
return builder.build();
3277
}
3378
}

src/main/resources/application-local.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,18 @@ logging:
5959
server:
6060
port: 8080
6161

62+
cloud:
63+
aws:
64+
region: ${AWS_REGION:ap-northeast-2}
65+
credentials:
66+
access-key: ${LOCAL_MINIO_ROOT_USER:docsa-local}
67+
secret-key: ${LOCAL_MINIO_ROOT_PASSWORD:docsa-local-password}
68+
s3:
69+
bucket: ${LOCAL_MINIO_BUCKET:docsa-local}
70+
endpoint: ${LOCAL_MINIO_ENDPOINT:http://localhost:9000}
71+
path-style-access-enabled: true
72+
public-base-url: ${LOCAL_MINIO_PUBLIC_BASE_URL:http://localhost:9000/docsa-local}
73+
6274
app:
6375
cors:
6476
allowed-origin:

0 commit comments

Comments
 (0)