Spring & Spring Boot/대용량 파일 전송 시스템 개발

[28] 대용량 파일 전송 시스템 개발 - 배포, Docker Container 실행, docker run / inspect / network / logs, host.docker.internal

carrotweb 2026. 10. 2. 16:13
728x90
반응형

Docker Container 실행

 

Docker Container 실행

도커 이미지로 컨테이너를 생성하여 백그라운드로 실행합니다.

docker run -d -p [호스트 포트]:[컨테이너 포트] --name {생성할 컨테이너 이름} {이미지의 이름(태그)}

-d : 컨테이너를 백그라운드 모드로 실행합니다.

-p : PC의 포트와 컨테이너 내부의 포트를 연결합니다.

 

docker run -d -p 8080:8080 --name dev-transmission transmission-app

 

 

도커 컨테이너 실행 실패

Docker Container 실행 Log 확인 (Docker Desktop에서 Logs 탭에서 확인할 수 있습니다.)

WARN 1 --- [transmission] [           main] ConfigServletWebServerApplicationContext : Exception encounter
ed during context initialization - cancelling refresh attempt: org.springframework.beans.factory.Unsatisfi
edDependencyException: Error creating bean with name 'download5Controller': Unsatisfied dependency express
ed through field 'downloadRedisService': Error creating bean with name 'downloadRedisServiceImpl': Unsatis
fieddependency expressed through field 'redisTemplateString': Error creating bean with name 'redisTemplate
String' defined in class path resource [com/example/transmission/config/RedisConfig.class]: Unsatisfied de
pendency expressed through method 'redisTemplateString' parameter 0: Error creating bean with name 'rediss
onConnectionFactory' defined in class path resource [org/redisson/spring/starter/RedissonAutoConfiguration
V2.class]: Unsatisfied dependency expressed through method 'redissonConnectionFactory' parameter 0: Error 
creating bean with name 'redisson' defined in class path resource [org/redisson/spring/starter/RedissonAut
oConfigurationV2.class]: Failed to instantiate [org.redisson.api.RedissonClient]: Factory method 'redisson
' threw exception with message: java.util.concurrent.ExecutionException: org.redisson.client.RedisConnecti
onException:Unable to connect to Redis server: 127.0.0.1/127.0.0.1:6379

 

스프링 부트 애플리케이션이 실행 중인 Redis 서버(127.0.0.1:6379)에 연결하지 못해 발생한 오류입니다.

 

이유는 Redis 컨테이너가 이미 실행 중인 상태에서 Spring Boot 컨테이너가 실행될 때 Redis 컨테이너가 사용 중인 네트워크와 같지 않기 때문입니다.

 

그래서 두 컨테이너가 사용하는 네트워크를 확인하여 동일한 네트워크로 설정해야 합니다.

 

Gemini AI와 OpenAI로 생성한 이미지입니다.

 

 

도커 컨테이너의 네트워크 이름 확인

Docker Inspect 실행

도커 컨테이너나 도커 이미지에 대한 상세한 저수준(low-level) 정보를 JSON 형식으로 출력합니다.

docker inspect {컨테이너 이름 또는 ID}
docker inspect dev-redis

 

Docker Inspect 실행 결과

[
    {
        “Id”: “6e132b25441c8e853b36b675b85fb0588aa6b595245a70f91d01d6b81b6189ee”,
        :
        “HostConfig": {
            :
            "NetworkMode": "bridge",
            :

 

네트워크의 이름은 [HostConfig > NetworkMode]에 설정되어 있습니다.

별도 네트워크를 설정하지 않았다면 기본값인 bridge(브리지)를 사용하게 됩니다.

 

-f(--format) 옵션을 사용하여 정보의 값을 추출할 수 있습니다.

docker inspect –f(--format) ’{{추출할 정보 경로}}’ {컨테이너 이름 또는 ID}
docker inspect -f '{{.HostConfig.NetworkMode}}' dev-redis

 

네트워크 정보 확인

        "NetworkSettings": {
            "SandboxID": "21c6416659835f8f37cf177fe87bd5b2ae91fb33d8f6beec43749a1bc14cf653",
            "SandboxKey": "/var/run/docker/netns/21c641665983",
            "Ports": {
                "6379/tcp": [
                    {
                        "HostIp": "0.0.0.0",
                        "HostPort": "6379"
                    },
                    {
                        "HostIp": "::",
                        "HostPort": "6379"
                    }
                ]
            },
            "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "DriverOpts": null,
                    "GwPriority": 0,
                    "NetworkID": "c2faa9169c0907ea7e8ce90a0420c3aff56ea9d32e6d7159c06354ff8f66f316",
                    "EndpointID": "f6d29a0e7ff134bceda31bb491e939d55271450654fca280dc5f825018eb4f4c",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.2",
                    "MacAddress": "4e:2f:b0:98:fa:f7",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "DNSNames": null
                }
            }
        },

 

Docker의 기본 bridge 네트워크는 컨테이너 이름을 통한 DNS 해석을 지원하지 않습니다.

그래서 사용자 정의 네트워크를 새로 만들어서 사용해야 합니다.

새로 만든 도커 네트워크로 모든 도커의 네트워크가 변경되어 실행되어야 합니다.

 

 

사용자 정의 도커 네트워크 생성

Docker Network 확인

모든 도커의 네트워크 목록을 출력합니다.

docker network ls

 

Docker Network 생성

도커 컨테이너들이 서로 통신할 수 있는 새로운 사용자 정의 네트워크를 생성합니다.

docker network create {생성할 네트워크 이름}
docker network create dev-network

 

Docker Network 연결

실행 중이거나 생성된 도커 컨테이너를 특정 도커 네트워크에 추가 연결합니다.

docker network connect {생성된 네트워크 이름} {컨테이너 이름 또는 ID}
docker network connect dev-network dev-redis

 

정상적으로 네트워크에 연결되었는지 네트워크 목록을 통해 확인합니다.

 

네트워크 정보 확인

docker inspect dev-redis
        "NetworkSettings": {
            "SandboxID": "21c6416659835f8f37cf177fe87bd5b2ae91fb33d8f6beec43749a1bc14cf653",
            "SandboxKey": "/var/run/docker/netns/21c641665983",
            "Ports": {
                "6379/tcp": [
                    {
                        "HostIp": "0.0.0.0",
                        "HostPort": "6379"
                    },
                    {
                        "HostIp": "::",
                        "HostPort": "6379"
                    }
                ]
            },
            "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "DriverOpts": null,
                    "GwPriority": 0,
                    "NetworkID": "c2faa9169c0907ea7e8ce90a0420c3aff56ea9d32e6d7159c06354ff8f66f316",
                    "EndpointID": "f6d29a0e7ff134bceda31bb491e939d55271450654fca280dc5f825018eb4f4c",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.2",
                    "MacAddress": "4e:2f:b0:98:fa:f7",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "DNSNames": null
                },
                "dev-network": {
                    "IPAMConfig": {},
                    "Links": null,
                    "Aliases": [],
                    "DriverOpts": {},
                    "GwPriority": 0,
                    "NetworkID": "6f751839b6bd66be31d2053acfd426836656202e5b5da0acd3c3875220a7d886",
                    "EndpointID": "c24298e5568510df96c0c910035c993314b2ec65a0fabf23f5c80191272ac023",
                    "Gateway": "172.20.0.1",
                    "IPAddress": "172.20.0.2",
                    "MacAddress": "1e:fd:1e:77:9c:ba",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "DNSNames": [
                        "dev-redis",
                        "6e132b25441c"
                    ]
                }
            }
        },

 

이제 동일한 네트워크에서 dev-redis로 Redis를 찾을 수 있게 되었습니다.

 

네트워크 IPAddress 대신 DNSName(컨테이너 이름)을 사용해야 하는 이유는 컨테이너가 재시작되거나 재생성될 때 IP가 바뀌기 때문입니다.

 

 

도커 컨테이너 내부에서 PC로 연결

데이터베이스가 도커 컨테이너가 아니라 PC에 설치되어 있습니다.
도커 컨테이너 내부에서 localhost나 127.0.0.1로 주소를 지정하면, PC가 아니라 도커 컨테이너 자체 내부를 가리키게 됩니다.

그래서 PC에 설치된 데이터베이스에 접속하지 못합니다. (에러 발생 : CannotGetJdbcConnectionException)

### Error querying database.  Cause: org.springframework.jdbc.CannotGetJdbcConnectionException:
Failed to obtain JDBC Connection


도커 컨테이너에서 PC에 있는 데이터베이스에 접근하기 위해서 PC를 가리키는 특수 도메인인 host.docker.internal을 사용하면 됩니다.

 

 

로컬 도커 환경에서 실행될 수 있게 LocalDocker 환경을 추가하여 사용하겠습니다.

 

1. pom.xml 파일에 로컬 도커 환경을 위한 profile를 추가합니다.

<profiles>
    :
    <profile>
        <id>LocalDocker</id>
        <properties>
            <activatedProperties>dck</activatedProperties>
        </properties>
    </profile>
    :
</profiles>

 

2. 기존 application-local.yml 파일을 복사하여 application-dck.yml 파일을 생성합니다. (로컬 도커 환경용)

datasource url를 localhost에서 host.docker.internal로 변경합니다.

redis host를 localhost에서 Redis의 컨테이너 이름인 dev-redis로 변경합니다.

redisson file를 redisson-local.yml에서 redisson-dck.yml로 변경합니다.

# Spring
spring:
  datasource:
    url: jdbc:mysql://host.docker.internal:3307/testdb
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: kiki@2000
  data:
    redis:
      host: dev-redis
      port: 6379
      password: kiki@2000
      ssl:
        enabled: false
      timeout: 5000ms
      lettuce:
        shutdown-timeout: 100ms
        pool:
          max-active: 5
          max-idle: 5
          min-idle: 3
          max-wait: 2000ms
  redis:
    redisson:
      file: classpath:redisson-dck.yml

# Log
logging:
  level:
    org:
      hibernate:
        type:
          descriptor:
            sql: trace

# Server
server:
  port: 8080

 

3. 기존 redisson-local.yml 파일을 복사하여 redisson-dck.yml 파일을 생성합니다. (로컬 도커 환경용)

redis host를 127.0.0.1에서 Redis의 컨테이너 이름인 dev-redis로 변경합니다.

singleServerConfig:
  address: "redis://dev-redis:6379"
  password: "kiki@2000"
  connectionPoolSize: 16
  connectionMinimumIdleSize: 6
  idleConnectionTimeout: 10000
  connectTimeout: 10000
  timeout: 3000

 

 

Docker Container 재 실행

1. 도커 컨테이너를 삭제합니다.

docker rm dev-transmission

 

2. 도커 이미지를 삭제합니다.

docker rmi transmission-app

 

3. 로컬 도커 환경으로 빌드 (프로젝트의 루트 디렉터리에서 빌드)

mvnw clean package -PLocalDocker -DskipTests

 

4. 도커 빌드 (프로젝트의 루트 디렉터리에서 빌드)

docker build --no-cache -t transmission-app .

 

5. 도커 컨테이너 실행

docker run -d -p [호스트 포트]:[컨테이너 포트] --name {생성할 컨테이너 이름} --network {생성된 네트워크 이름} {이미지의 이름(태그)}

-network : 도커 네트워크에 연결합니다.

 

docker run -d -p 8080:8080 --name dev-transmission --network dev-network transmission-app

 

도커 실행 시 볼륨 연결 (PC 업로드 경로와 도커 컨테이너 내부 경로와 연결)

docker run -d -p [호스트 포트]:[컨테이너 포트] --name {생성할 컨테이너 이름} --network {생성된 네트워크 이름} -v [호스트 디렉터리]:[컨테이너 내부 디렉터리] {이미지의 이름(태그)}

-v : 호스트 디렉터리와 컨테이너 내부 디렉터리를 마운트(연결)합니다.

 

docker run -d -p 8080:8080 --name dev-transmission --network dev-network -v "C:/tempUpload/data:/appdata/upload" transmission-app

 

네트워크 정보 확인

docker inspect dev-transmission
        "NetworkSettings": {
            "SandboxID": "c9779dcc9078bf20d71929a953b233de75f1bb87ac98d68c76efd6e6bd44e4d6",
            "SandboxKey": "/var/run/docker/netns/c9779dcc9078",
            "Ports": {
                "8080/tcp": [
                    {
                        "HostIp": "0.0.0.0",
                        "HostPort": "8080"
                    },
                    {
                        "HostIp": "::",
                        "HostPort": "8080"
                    }
                ]
            },
            "Networks": {
                "dev-network": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "DriverOpts": null,
                    "GwPriority": 0,
                    "NetworkID": "6f751839b6bd66be31d2053acfd426836656202e5b5da0acd3c3875220a7d886",
                    "EndpointID": "c6bd1b7840361204af2150d76f9836a38876b4bd0cce0357279327b0ac9d1067",
                    "Gateway": "172.20.0.1",
                    "IPAddress": "172.20.0.3",
                    "MacAddress": "82:c0:a2:d8:d0:7d",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "DNSNames": [
                        "dev-transmission",
                        "dc2b1f4737f2"
                    ]
                }
            }
        },

 

도커에서 정상적으로 실행되는 것을 확인할 수 있습니다.

 

 

docker logs 실행

실행 중이거나 종료된 도커 컨테이너의 표준 출력(stdout) 및 표준 에러(stderr) 로그를 확인할 수 있습니다.

docker logs {컨테이너 이름 또는 ID}
docker logs dev-transmission

 

로그가 출력되고 종료됩니다.

 

docker logs -f dev-transmission

-f(--follow): 로그를 실시간으로 계속 출력합니다.

 

로그가 출력되고 종료하지 않고 유지합니다.

 

docker logs -f --tail 10 dev-transmission

-tail {줄 수}: 로그 끝을 기준으로 이전 줄 수만큼 출력합니다.

 

로그 끝을 기준으로 이전 10줄만 출력하고 종료하지 않고 유지합니다.

 

docker logs -f --since 8m dev-transmission

--since {시/분/초}: 로그를 출력할 시작 시(h)/분(m)/초(s)를 지정합니다.

 

로그에서 최근 8분 동안 발생한 로그를 출력하고 종료하지 않고 유지합니다.

 

 

728x90
반응형