안녕하세요! 오늘은 Docker로 Redis 컨테이너를 실행하고, 로컬 터미널에서 redis-cli로 접속했는데 환경은 분리되어 있는데 컨테이너 속 데이터가 그대로 보이는 경우가있어서 궁금해서 찾아본 결과를 작성하였습니다.  

사건의 발단

새로운 프로젝트를 위해 터미널에 익숙한 명령어를 입력합니다.

docker run --name my-redis -p 6379:6379 -d redis

 

my-redis라는 이름의 컨테이너가 백그라운드에서 잘 실행되고 있습니다. 이제 데이터가 잘 들어가는지 확인하기 위해, 새로운 터미널 창을 열고 redis-cli에 접속해봅니다.

# 새로운 터미널 창
redis-cli

127.0.0.1:6379> keys *
1) "RT:user123"
2) "post:likes:42"
... (애플리케이션이 저장한 키 목록)

 

그런데 이상합니다. 저는 분명 Docker 컨테이너 안에 Redis를 띄웠는데, 어떻게 로컬 PC에서 실행한 redis-cli가 컨테이너 속 데이터를 보고 있는 걸까요? 마치 내 컴퓨터에 직접 Redis를 설치한 것처럼 말이죠.

혹시 내가 모르는 사이에 로컬에도 Redis가 설치되어 있었나? 데이터가 복사라도 된 건가? 이런저런 생각에 잠시 혼란에 빠집니다.

범인은 바로 '포트 포워딩'

결론부터 말하면, 이것은 버그나 실수가 아닌 Docker의 매우 유용한 기능 덕분입니다. 범인은 바로 docker run 명령어에 사용했던 -p 6379:6379 옵션, 즉 **포트 포워딩(Port Forwarding)**입니다.

-p 옵션은 [호스트 포트]:[컨테이너 포트] 형식을 가집니다.

-p 6379:6379
"이 PC(호스트)의 6379번 포트로 들어오는 모든 네트워크 요청을, 저 Docker 컨테이너 내부의 6379번 포트로 전달(포워딩)해주세요."

 

마치 전화기의 '착신 전환' 기능과 같습니다. 내 자리(localhost:6379)로 걸려 온 전화를 지정된 다른 번호(Docker 컨테이너)로 자동으로 연결해주는 것이죠.

우리가 터미널에서 아무 옵션 없이 redis-cli를 실행하면, 이 프로그램은 기본적으로 localhost6379번 포트로 접속을 시도합니다. 이때 Docker가 이 요청을 가로채서 my-redis 컨테이너 안으로 투명하게 전달해주기 때문에, 우리는 마치 로컬에 직접 접속하는 것처럼 컨테이너 내부의 Redis와 통신할 수 있었던 것입니다.

직접 증명해보기: 컨테이너 속으로 직접 들어가보자

"정말 그런지 내 눈으로 확인해야겠어!" 라고 생각하신다면, docker exec 명령어로 컨테이너 안에서 직접 redis-cli를 실행해볼 수 있습니다.

# 실행 중인 'my-redis' 컨테이너 안에서 'redis-cli keys *' 명령어를 실행
docker exec my-redis redis-cli keys '*'

결과는 어떨까요? 놀랍게도(혹은 당연하게도) 로컬에서 실행했을 때와 완벽하게 똑같은 키 목록이 출력됩니다.

이것으로 데이터는 오직 Docker 컨테이너 안에만 존재하며, 로컬에서의 접속은 포트 포워딩이라는 가상의 통로를 통한 '원격 접속'이었음이 증명되었습니다.

 

 

마치며

이 간단한 원리 덕분에 개발자는 큰 축복을 받습니다. Spring Boot 애플리케이션의 application.yml 파일에 spring.redis.host=localhost 라고 설정하기만 하면 되고, IntelliJ 같은 IDE의 데이터베이스 툴에서도 localhost로 손쉽게 접속하여 데이터를 확인할 수 있습니다.

이제 Docker로 Redis를 띄우고 로컬에서 데이터가 보일 때 더 이상 당황하지 마세요. 그것은 여러분의 개발 경험을 한결 편하게 만들어주는 Docker의 똑똑한 마법이니까요

1. 문제 상황

Spring Boot 애플리케이션에서 Redis 연결 설정을 완료한 후, 애플리케이션을 실행했지만 다음과 같은 에러가 발생했습니다:

org.springframework.data.redis.RedisConnectionFailureException: Unable to connect to Redis
Caused by: java.net.ConnectException: Connection refused

이 에러는 Redis 서버와 애플리케이션이 제대로 통신하지 못하는 경우에 발생합니다.


2. 문제 원인

  • Redis 서버가 실행되지 않음
  • Redis 설정 파일에서 외부 접근을 허용하지 않음
  • Spring Boot의 Redis 설정에서 호스트가 잘못 지정됨
  • Docker 네트워크 문제: 애플리케이션과 Redis 컨테이너가 서로 다른 네트워크에 속해 있음
  • 포트 문제: Redis가 사용하는 포트(기본: 6379)가 열려 있지 않음

3. 해결 방법

Redis를 EC2에 직접 설치하거나 Docker를 통해 Redis 컨테이너를 설정하여 문제를 해결할 수 있습니다. 저는 Docker 환경에서 해결한 과정을 아래에 공유합니다.


4. Docker 환경에서 Redis 설정 및 문제 해결

4.1 Redis와 Spring Boot 애플리케이션이 통신할 네트워크 생성

먼저, Docker 컨테이너 간의 통신을 위해 네트워크를 생성합니다.

docker network create social-network

4.2 Redis 컨테이너 실행

Redis 컨테이너를 실행하면서, 이전에 생성한 네트워크(social-network)에 연결합니다.

docker run -d \\
  --name redis \\
  --network social-network \\
  -p 6379:6379 \\
  redis

  • -name redis: 컨테이너 이름을 redis로 설정
  • -network social-networksocial-network 네트워크에 연결
  • p 6379:6379: Redis의 기본 포트를 EC2에서 열어줌

4.3 Spring Boot 컨테이너 실행

Spring Boot 애플리케이션 컨테이너도 같은 네트워크에 연결하여 실행합니다.

docker run -d \\
  --name social-media \\
  --network social-network \\
  -p 8080:8080 \\
  -e AWS_S3_ACCESS_KEY=$AWS_S3_ACCESS_KEY \\
  -e AWS_S3_BUCKET_NAME=$AWS_S3_BUCKET_NAME \\
  -e AWS_S3_REGION=$AWS_S3_REGION \\
  -e AWS_S3_SECRET_KEY=$AWS_S3_SECRET_KEY \\
  <도커이미지이름>:latest
  • -network social-network: Redis와 같은 네트워크에 연결
  • Redis와 동일한 네트워크에 연결하지 않으면 Connection refused 에러가 발생합니다.

4.4 Spring Boot 설정 변경

Spring Boot 애플리케이션의 application.yml에서 Redis 호스트 이름을 redis로 변경합니다.

spring:
  data:
    redis:
      host: redis
      port: 6379
  • host: redis: Docker 네트워크 내에서 Redis 컨테이너의 이름을 호스트로 지정

4.5 컨테이너 상태 확인

컨테이너들이 제대로 실행되고 있는지 확인합니다.

docker ps

출력

CONTAINER ID   IMAGE                              COMMAND                  CREATED         STATUS         PORTS                                       NAMES
0d2f25acb373   redis                              "docker-entrypoint.s…"   2 minutes ago   Up 2 minutes   0.0.0.0:6379->6379/tcp, :::6379->6379/tcp   redis
de6bb85de644   <image이름>  			  "java -Dspring.profi…"   2 minutes ago   Up 2 minutes   0.0.0.0:8080->8080/tcp, :::8080->8080/tcp   <설정한 이름>

5. Redis 연결 테스트

Spring Boot 애플리케이션 내에서 Redis 연결이 제대로 이루어졌는지 확인합니다.

5.1 컨테이너 내부에서 Redis CLI 테스트

social-media 컨테이너 내부에서 Redis CLI를 설치한 후 Redis에 연결해보세요.

docker exec -it social-media bash

내부에서 Redis CLI를 설치하고 연결 테스트를 수행합니다.

apt-get update && apt-get install redis-tools -y
redis-cli -h redis -p 6379 ping

출력 

PONG
  • PONG 응답이 나오면 Redis와의 연결이 성공적으로 이루어진 것입니다.

6. 해결

위 과정을 통해 Spring Boot 애플리케이션이 Redis와 성공적으로 연결되었습니다. 이제 애플리케이션에서 Redis를 사용하는 기능을 정상적으로 실행할 수 있습니다.


7. 참고 명령어

  • Docker 네트워크 생성:
  • docker network create social-network
  • Redis 컨테이너 실행:
  • docker run -d --name redis --network social-network -p 6379:6379 redis
  • Spring Boot 애플리케이션 컨테이너 실행:
  • docker run -d --name social --network social-network -p 8080:8080

이렇게 문제를 해결하면 Spring Boot 애플리케이션과 Redis 간의 Connection refused 에러를 효과적으로 해결할 수 있습니다. 

Docker 컨테이너에서 S3 관련 에러가 발생한 경우 원인은 대부분 환경 변수가 제대로 설정되지 않은 것입니다.

이번 포스팅에서는 환경 변수를 설정하고 Docker 컨테이너에 적용하는 다양한 방법을 정리해 보겠습니다.


🛑 문제 발생

Docker Hub에서 이미지를 pull 한 뒤 run 명령어를 실행했으나, 다음과 같은 S3 관련 에러가 발생했습니다.

원인 분석

컨테이너에서 필요한 S3 환경 변수(예: AWS_S3_ACCESS_KEYAWS_S3_BUCKET_NAME 등)가 설정되지 않은 것이 원인입니다.


✅ 해결 방법

1️⃣ .env 파일 사용

Docker 컨테이너 실행 시, 필요한 환경 변수를 .env 파일에 저장하여 설정할 수 있습니다.

1. .env 파일 작성

아래와 같은 형식으로 .env 파일을 작성합니다:

AWS_S3_ACCESS_KEY=your-access-key
AWS_S3_SECRET_KEY=your-secret-key
AWS_S3_BUCKET_NAME=your-bucket-name
AWS_S3_REGION=your-region

2. Docker 컨테이너 실행

컨테이너 실행 시 .env 파일을 로드하여 환경 변수를 적용합니다:

docker run -p 8080:8080 --env-file=.env -d --name social <이미지이름>

다른 해결 방법들

2️⃣ Spring Boot 프로젝트 내 환경 변수 통합

만약 Spring Boot 프로젝트를 Docker 이미지로 빌드한 경우 환경 변수를 Spring Boot의 application.yml 또는 application.properties에 매핑할 수 있습니다.

1. application.yml 설정

application.yml 파일에 아래와 같이 환경 변수를 매핑합니다:

cloud:
  aws:
    credentials:
      access-key: ${AWS_S3_ACCESS_KEY}
      secret-key: ${AWS_S3_SECRET_KEY}
    region:
      static: ${AWS_S3_REGION}
    s3:
      bucket: ${AWS_S3_BUCKET_NAME}

2. Dockerfile 수정

.env 파일을 Docker 빌드 과정에 포함시킵니다:

COPY .env /app/.env

3. 컨테이너 실행

컨테이너 실행 시 .env 파일에 설정된 값을 사용합니다:

docker run -p 8080:8080 -d --name social <이미지이름>

3️⃣ Docker Compose 활용

Docker Compose를 사용하면 환경 변수를 보다 편리하게 관리할 수 있습니다.

1. docker-compose.yml 작성

.env 파일을 Docker Compose와 함께 사용할 수 있도록 설정합니다:

version: '3.8'
services:
  app:
    image: <이미지이름>
    ports:
      - "8080:8080"
    env_file:
      - .env

2. Docker Compose 실행

docker-compose up -d

 정리

  • Docker 환경 변수 설정은. env 파일, Spring Boot 설정, 또는 Docker Compose를 통해 간단히 해결할 수 있습니다.
  • 권장되는 방법은. env 파일과 Docker Compose를 조합하여 관리하는 방식입니다.

Docker 이미지를 빌드하거나 실행하는 과정에서 플랫폼 설정이 맞지 않아 경고 메시지가 발생하는 경우가 있습니다.

이번 포스팅에서는 Docker 플랫폼 미스매치 문제의 원인 해결 방법을 간단히 정리해 보겠습니다.


🛑 문제 발생

Docker 이미지를 빌드하는 중 아래와 같은 경고 메시지가 나타났습니다:

원인 분석

  • 호스트 플랫폼 (linux/amd64/v3)과 Docker 이미지 플랫폼 (linux/arm64/v8)이 서로 다른 경우 발생.
  • 기본적으로 Docker는 호스트 환경과 동일한 플랫폼을 사용합니다. 그러나 플랫폼을 명시하지 않으면 특정 상황에서 호환되지 않는 플랫폼으로 빌드될 수 있습니다.

 해결 방법

1️⃣ 플랫폼 명시하여 빌드

경고를 방지하려면 플랫폼을 명시적으로 설정하여 이미지를 빌드합니다.
아래 명령어를 실행하면 문제가 해결됩니다

docker build --platform linux/amd64 -t <이름> .

2️⃣ 이미지 실행 및 확인

정상적으로 빌드된 이미지를 실행한 후 컨테이너 상태를 확인합니다

docker run -p 8080:8080 -d --name social <이름>

컨테이너 상태 확인

docker ps

컨테이너가 정상적으로 실행 중이라면 다음과 같이 출력됩니다:


 요약

  • Docker 플랫폼 미스매치 오류는 호스트와 Docker 이미지의 플랫폼이 다를 때 발생합니다.
  • 빌드 시 --platform 옵션을 사용해 호환되는 플랫폼을 명시하면 문제를 해결할 수 있습니다.

 

 

 

 

 
 

+ Recent posts