본문 바로가기

Issue

[Docker] 도커 컴포즈를 통해 도커를 관리하다 생긴 문제들 - (1) (Docker Network)

이번 방학에 팀으로 프로젝트를 하나 진행하고 있었다. 게임제작과 관련된 부분인데 해당 프로젝트에서 서버 쪽을 담당하게 되었다.
기간은 올해 말까지로 예상중이고, 해당 프로젝트에서 방학에는 인증서버 제작과 Docker를 사용해 보는 것이 목표였다

 

1) 도커로 로컬환경을 공유해보자

아직 도커라는 것에 대해 이론적으로 부족한 부분들이 많았고, 내 로컬환경의 도커에서 사용 중인 ScyllaDB와 Redis 그리고 로컬에서 동작하는 Golang으로 제작된 인증서버도 Dockerfile로 빌드해서 컨테이너로 만든 뒤에 이 3개의 컨테이너를 다른 사람들에게 쉽게 공유할 수 있게 해보고 싶은 막연한 생각으로 시작해 보게 되었다.

 

2) 인증서버를 Docker로 관리해 보자

기존에는 Docker를 통해 Scylla, Redis의 이미지를 pull 해온 상황에서 컨테이너로 만들어 사용했고,
Golang으로 제작된 서버는 그냥 로컬에서 실행하여 사용했다. 당장에 Docker Compose를 통해 scylla, redis 이 두 개만 관리하고 golang 서버는 그냥 git을 통해 공유해 Docker Compose를 빌드해 사용하고 golang 서버는 로컬에서 따로 실행시켜서 사용해도 되지만, 나중에 인증서버 말고도 게임과 직접적으로 통신할 서버들이 추가될 예정이라 모든 것들의 코드를 일일이 공유해 주고 다 따로 실행시켜 관리하지 복잡해질 것 같았다. 그래서 인증서버를 이미지로 만들어 빌드한 뒤에 컨테이너에서 관리할 수 있게 해 두고 Docker Compose를 통해 한번에 인증서버-scylla-redis (이후에는 추가되는 서버들까지) 이 세 개를 관리할 수 있게끔 만들 수 있게끔 해두려고 했다.

 

3) Docker Network

로컬에서 인증서버를 실행할 때 ScyllaDB와 redis에 연동을 할 땐, localhost:포트를 통해 연동을 할 수 있었다.

// ScyllaDB 클라이언트 설정
	cluster := gocql.NewCluster("localhost:9042")
	cluster.Keyspace = "keycap_auth"
	cluster.ProtoVersion = 4
	session, err := cluster.CreateSession()
	if err != nil {
		log.Fatal(err)
	}
	defer session.Close()

// Redis 클라이언트 설정
	rdb := redis.NewClient(&redis.Options{
		Addr: "localhost:6379", // Redis 서버 주소
	})
	_, err = rdb.Ping(context.Background()).Result()
	if err != nil {
		log.Fatal(err)
	}

인증서버를 Docker를 통해 실행시켜 컨테이너에 올리게 되면 사용되는 localhost 주소는 컨테이너 내부의 localhost를 찾게 되기 때문에, scylla와 redis 컨테이너를 찾을 수 없게 된다.
계속해서 인증서버가 ScyllaDB의 주소인 9042번 포트에 연결이 되지 않아 에러가 발생해 강제종료 되었고,
초기에는 해당 문제의 원인을 scylla 컨테이너 config의 외부포트 차단 때문이라고 생각했다.


따라서 초기에는 scylla 이미지를 빌드할 때, 옵션값을 추가하여 listen-address와 rpc-address의 주소를 0.0.0.0으로 설정해 두었다.
command: "--network-stack posix --developer-mode 1 --overprovisioned 1 --listen-address 0.0.0.0 --rpc-address 0.0.0.0 --seed-provider-parameters seeds=0.0.0.0 --alternator-address 0.0.0.0 --blocked-reactor-notify-ms 999999999 --alternator-port 8000 --alternator-write-isolation always"

그러나 아래와 같이 설정값들이 중복된다는 에러문이 출력되었고,

2023-08-19 17:22:37 scylla | error: option network-stack cannot be specified more than once

해당 문제를 해결하기 위해 로컬 내의 디렉토리에 scylla의 config를 수정해 놓고 마운트시켜 문제를 해결하려고 하였다

volumes:
    - ./scylla:/var/lib/scylla
    - /data/scylla:/etc/scylla

기존에 Docker Compose를 활용하기 위해 컨테이너를 지우고 다시 생성하려 했는데 데이터를 복원하기 위해 scylla data를 로컬 디렉토리 내부에 마운트 시켜놓았기 때문에 마찬가지로 config도 위와 같이 해놓으려고 했었다.

그렇게 다시 컨테이너를 생성하고 인증서버를 실행시켰지만, 여전히 Scylla에 접속할 수 없었다.
뭔가 이상함을 느끼고 config와 기존 DB의 정보들이 정상적으로 복원되었는지 확인하기 위해서 docker 내부에 접속하여 cqlsh를 통해 DB를 접속하려 했지만 접속이 안되어 문제가 있다고 판단하고 바로 다른 방법을 찾아보게 되었다.

 

그렇게 찾아보다 Docker Network라는 개념에 대해서 알게 되었다. Docker Network는 컨테이너 간 통신을 관리하기 위해 사용되며, 컨테이너를 서로 연동하거나 컨테이너와 호스트 간의 통신을 위해 사용된다.
여러 가지 종류가 있지만 기본적인 Bridge Network를 사용하였고, keycap-network라는 사용자 정의 네트워크를 생성해 해당 네트워크에 scylla, redis, 인증서버 컨테이너를 연결하여 사용하였다.

 

컨테이너 명을 기준으로 통신하기 때문에 기존에 사용하던 localhost 대신 컨테이너명을 사용한 주소값으로 연동하였다.

// ScyllaDB 클라이언트 설정
	cluster := gocql.NewCluster("scylla:9042")
	cluster.Keyspace = "keycap_auth"
	cluster.ProtoVersion = 4
	session, err := cluster.CreateSession()
	if err != nil {
		log.Fatal(err)
	}
	defer session.Close()

// Redis 클라이언트 설정
	rdb := redis.NewClient(&redis.Options{
		Addr: "redis:6379", // Redis 서버 주소
	})
	_, err = rdb.Ping(context.Background()).Result()
	if err != nil {
		log.Fatal(err)
	}


위와 같이 설정하여 컨테이너 간 통신을 지원하기 위해 네트워크 설정을 추가하여 docker-compose 파일을 작성하여 빌드하였다.
이후 포스팅에선 생긴 작은 이슈와 함께 Docker Compose 파일의 작성 과정에 대해 다룬다.