failed to start docker container: Error response from daemon: ports are not available: exposing port TCP 0.0.0.0:54322 -> 127.0.0.1:0: /forwards/expose returned unexpected status: 500
Try rerunning the command with --debug to troubleshoot the error.
에러 메세지에 대해 찾아보니 이미 사용하고 있는 포트여서 발생하는 현상이라는 글들이 있어 netstat -ano 명령어를 통해 사용중인 포트를 확인하고 원하는 포트에서 실행되고 있는 프로그램의 PID를 알아내어 종료시키면 된다는 글들이 있었다.
하지만 나의 경우 해당 명령어를 실행해도 3000번 포트에서 실행되고 있는 프로그램이 존재하지 않았다.
좀더 서칭을 해본 결과 어떤 블로그에서 해결방안을 찾을 수 있었다.
netsh interface ipv4 show excludedportrange protocol=tcp
위 명령어를 입력하면
다음과 같이 포트 제외범위가 나오는데 이 범위안에 사용하려고 하는 포트가 포함되어있으면 제목의 오류메시지와 함께 오류가 발생한다. 나는 54322 포트가 포함이 되어있었다.
WSL2 Ubuntu 환경에서 Spring Boot 프로젝트를 빌드하던 중 다음과 같은 오류가 발생했다.
$ docker-compose up -d
Error response from daemon: client version 1.42 is too old.
Minimum supported API version is 1.44, please upgrade your client to a newer version
환경 정보
OS: WSL2 Ubuntu 24.04
Docker Desktop: 27.5.1 (Windows)
Docker CLI (WSL): 1.42 (구버전)
Spring Boot: 3.5.4
원인
Docker Desktop과 WSL CLI 버전 불일치
WSL + Docker Desktop 환경에서는 두 가지 Docker 컴포넌트가 존재한다.
Docker Desktop (Windows): 최신 버전 (27.5.1)
실제 컨테이너를 실행하는 엔진
Docker CLI (WSL): 구버전 (1.42)
WSL에서 명령어를 입력받는 클라이언트
문제는 WSL의 Docker CLI가 오래되어 Docker Desktop의 최신 API(1.44)와 통신할 수 없다는 것이었다.
Dockerfile은 사용자가 이미지를 어셈블하기 위해 호출할 수 있는 명령이 포함된 간단한 텍스트 파일인 반면, Docker Compose는 다중 컨테이너 Docker 애플리케이션을 정의하고 실행하기 위한 도구입니다.
Docker Compose는 앱을 구성하는 서비스를 docker-compose.yml에 정의하여 격리된 환경에서 함께 실행할 수 있습니다. docker-compose up을 실행하여 하나의 명령으로 앱을 실행합니다. 프로젝트의 docker-compose.yml에 빌드 명령을 추가하면 Docker compose는 Dockerfile을 사용합니다. Docker 워크플로는 생성하려는 각 이미지에 적합한 Dockerfile을 빌드한 다음 compose를 사용하여 build 명령을 사용하여 이미지를 조합하는 것이어야 합니다.
Dockerfile
목적
이미지를 어셈블하기 위해 호출할 수 있는 명령이 포함된 간단한 텍스트 파일
단일 Docker 이미지를 빌드하기 위한 명세서
이 파일에는 베이스 이미지 선택, 추가 파일 복사, 환경 변수 설정, 필요한 소프트웨어 설치, 컨테이너 실행 시 실행할 명령어 등 이미지를 생성하기 위한 모든 명령어가 포함
기능
Docker 이미지를 생성
이 이미지는 애플리케이션과 그 애플리케이션을 실행하는 데 필요한 모든 종속성을 포함
이미지는 컨테이너를 생성하는 데 사용
사용 예시
보통 애플리케이션 개발 과정에서 특정 서비스나 애플리케이션의 빌드 방식을 정의할 때 사용
Node.js 애플리케이션을 위한 Dockerfile은 Node.js 환경을 설정하고 애플리케이션 코드를 이미지 내부로 복사하는 명령어를 포함할 수 있다.
Docker Compose
목적
앱을 구성하는 서비스를 docker-compose.yml에 정의하여 docker-compose up을 실행하여 하나의 명령으로 앱을 실행
즉, 앱이 실행되는 동안 컨테이너를 관리하는 역할
앱이 시작되면 컨테이너를 띄우고 앱이 실행되는 중에 컨테이너가 종료되면 다시 띄워줌
여러 Docker 컨테이너를 정의하고 실행하기 위한 도구인 Docker Compose의 설정 파일
이 파일에서는 애플리케이션을 구성하는 여러 서비스(예: 데이터베이스, 백엔드 애플리케이션, 프론트엔드 애플리케이션 등)를 정의하고, 각 서비스에 대한 이미지, 포트 매핑, 볼륨 마운트, 네트워크 설정 등을 지정
기능
여러 컨테이너의 배포 및 관리를 단순화
docker-compose 명령어를 사용하여 모든 서비스를 한 번에 시작, 중지, 재구축할 수 있다.
사용 예시
docker-compose.yml은 마이크로서비스 아키텍처 또는 여러 종속성을 가진 복잡한 애플리케이션을 로컬 개발 환경이나 테스트 환경에서 실행할 때 주로 사용
예를 들어, 웹 애플리케이션, 관련 데이터베이스, 그리고 그것들을 연결하는 네트워크를 동시에 정의하고 실행할 수 있다.
docker-compose.yml 파일에서 Dockerfile의 경로를 통해 Dockerfile에 정의된 이미지를 관리할 수도 있다.
그래서 docker-compose.yml에서 빌드에 대한 내용이 어떻게 나타나 있는지 찾아보게 되었고 docker 공식 홈페이지에서 이런 내용을 찾아 볼 수 있었다.
As with docker run, options specified in the Dockerfile, such as CMD, EXPOSE, VOLUME, ENV, are respected by default - you don’t need to specify them again in docker-compose.yml.
Dockerfile에서 나타난 CMD, EXPOSE, VOLUME, ENV에 관한 내용에 따라서 빌드가 되기 때문에 이에 관련된 내용은 docker-compose.yml에서 따로 나타낼 필요는 없다.
파일 내 volumes 설정은 Docker 안에서 실행되는 리눅스의 /docker-entrypoint-initdb.d/ , var/lib/mysql 폴더가 docker-compose.yml 파일이 원래 있는 경로에 database 폴더를 생성하고, 그 아래의 init, datadir 에 생성되도록 한다.
원래 docker는 종료되면 docker에서 실행된 내용들은 모두 사라진다.
이렇게 docker를 실행하는 컴퓨터 쪽의 디스크와 마운트 시킴으로써 사라지지 않고 계속 사용할 수 있게 할 수 있다.
# docker-compose.yml의 일부 volumes: - ./database/init/:/docker-entrypoint-initdb.d/ - ./database/datadir/:/var/lib/mysql
docker-compose.yml 파일이 있는 경로
docker-compose.yml 파일이 있는 곳에 database 폴더가 있는 것을 볼 수 있다.
해당 폴더 안에 mysql의 data가 저장된다.
docker-compose down 명령을 실행하면 mysql 서버가 종료된다. database 폴더를 삭제하고 다시 실행하면 모든 데이터가 삭제된다. (주의)
docker ps 명령으로 실행되는 이미지에서 container id를 복사 후 mySQL이미지에 접속한다.
> docker ps
# mysql 접속
> docker exec -it {복사한conainterID} /bin/bash
그럼 끝났다.
* Docker-Desktop을 이용해 Redis를 실행
위의 과정을 통해 도커가 설치되어 있다는 가정 하에 아래를 진행한다.
1. 도커 폴더 아래 redis 폴더를 생성한다.
2. redis폴더 아래 docker-compose.yml 작성한다.
services:
redis:
image: redis:latest # 최신 Redis 이미지를 사용
container_name: redis
command: ["redis-server", "--requirepass", "{password}", "--appendonly", "yes"]
ports:
- "6379:6379" # 로컬의 6379 포트를 Redis 컨테이너의 6379 포트에 매핑
volumes:
- ./redis-data:/data # 로컬의 'redis_data' 볼륨을 컨테이너의 /data 디렉토리에 매핑하여 데이터 영속성 유지
volumes:
redis-data:
3. 터미널을 열어서 아래의 명령어를 입력한다.
# 레디스 이미지 가져오기
> docker pull redis
# 이미지 가져왔는지 확인
> cker images
# 레디스 실행
> docker compose up -d
> docker ps
# 레디스 컨테이너 접속
> docker exec -it {레디스 컨테이너 아이디} redis-cli
# 레디스 암호
> AUTH {password}
# 모든 키 검색
> KEYS *
# 키 값 출력
> KEYS refreshToken:*
# 해당 키에 대한 값 출력
> GET {키 값}
# 해당키의 유효 시간 출력
> TTL {키 값}
# 해당키 삭제
> DEL {키 값}