블로그
전체 7#카테고리
- 개발 · 프로그래밍 기타
#태그
- Docker

2025. 10. 10.
0
AWS EC2에서 Docker를 활용해 배포해보기
Ubuntu에서 Docker, Docker Compose 설치하기Ubuntu에서 Docker, Docker Compose 설치하기sudo apt-get update && \ sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common && \ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - && \ sudo apt-key fingerprint 0EBFCD88 && \ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" && \ sudo apt-get update && \ sudo apt-get install -y docker-ce && \ sudo usermod -aG docker ubuntu && \ newgrp docker && \ sudo curl -L "https://github.com/docker/compose/releases/download/2.27.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose && \ sudo chmod +x /usr/local/bin/docker-compose && \ sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose 잘 설치됐는지 확인docker -v # Docker 버전 확인 docker compose version # Docker Compose 버전 확인 AWS ECR(Elastic Container Registry)이 뭘까? 왜 배울까?AWS ECR이 뭘까?필요한 이미지를 다운로드 받을 때 Dockerhub이라는 곳에서 다운받는다고 했었다. Dockerhub에서는 이미지를 저장 및 다운받을 수 있는 저장소 역할을 한다고도 했다. Dockerhub과 동일한 역할을 하는 서비스가 하나 더 있다. 그게 바로 AWS ECR이다. AWS ECR도 이미지를 저장 및 다운받을 수 있는 저장소 역할을 한다. 우리는 이 AWS ECR에 대해 배울 것이다. 왜 Dockerhub 대신에 AWS ECR을 사용하는가?최근에는 AWS 클라우드 환경에서 인프라를 구축하는 일이 많아졌다. AWS ECR을 사용하면 다른 AWS Resource와의 연동이 편하고, AWS 내에서 한 번에 관리할 수 있기에 편하다는 장점이 있다. AWS ECR을 왜 배우는지?Docker를 사용하지 않았을 때 많은 사람들이 사용하는 배포 전략 중 하나는 Github을 활용하는 방법이다. 프로젝트 코드를 Github에 Push 한 뒤에, AWS EC2에 접속해서 해당 코드를 Pull 받아서 실행시키는 방식을 많이 사용한다. 이 방식은 프로젝트 코드 전체를 EC2로 이동시켜야 하며, 프로젝트 코드를 실행시킬 런타임 환경(Node, JDK 등)도 설치되어 있어야만 실행이 된다. Docker의 가장 큰 장점은 이식성이다. Docker만 깔려있으면 어디에서든 내가 원하는 프로젝트를 실행시킬 수 있다는 게 장점이다. 이 때 Github을 활용해 프로젝트 코드 전체를 EC2로 옮겨 Docker 기반으로 실행시켜도 된다. 하지만 프로젝트에서 필요한 코드에 대해서만 Docker 이미지로 빌드해, EC2에서는 그 이미지만 다운받아서 실행시키는 게 훨씬 심플하다. AWS ECR을 배우는 이유는 훨씬 간단하게 프로젝트를 배포하고 실행시키기 위해서이다. [실습] AWS ECR(Elastic Container Registry) 사용해보기[맥(Mac OS)]brew install awscli aws --version # 잘 출력된다면 정상 설치된 상태[윈도우(Windows)]이 링크(https://awscli.amazonaws.com/AWSCLIV2.msi)를 다운받아 설치하기cmd를 실행시켜서 아래 명령어 입력해보기aws --version # 잘 출력된다면 정상 설치된 상태[우분투(Ubuntu)]sudo apt install unzip curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" unzip awscliv2.zip sudo ./aws/install $ aws --version # 잘 출력된다면 정상 설치된 상태 -- IAM 생성하기IAM에서 사용자 생성하기Access Key 발급하기AWS CLI로 액세스 키 등록하기aws configure AWS Access Key ID [None]: AWS Secret Access Key [None]: Default region name [None]: ap-northeast-2 Default output format [None]: -- AWS ECR(Elastic Container Registry) 셋팅하기Docker 이미지를 저장할 수 있는 저장소를 만들어보자. 일반적으로 하나의 리포지토리에는 한 종류의 이미지만 저장하고 관리한다. -- 이미지 빌드해서 AWS ECR에 Push, Pull 해보기Dockerfile 작성하기FROM openjdk:17-jdk ENTRYPOINT ["/bin/bash", "-c", "sleep 500"] 이미지 빌드 및 push 하기 aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin ... docker build --platform linux/amd64 -t hwiro-web-server . docker tag hwiro-web-server:latest ... docker push ... 이미지 pull 받아보기 docker image rm -f [Container ID] # 기존 갖고있던 이미지 지우기 docker pull 002177417362.dkr.ecr.ap-northeast-2.amazonaws.com/instagram-server docker image ls002177417362.dkr.ecr.ap-northeast-2.amazonaws.com/instagram-server : 이 값 자체가 이미지 이름이다. 길어서 어색해보일 뿐이다. [실습] AWS EC2에 Spring Boot 배포하기로컬 환경에서 프로젝트 셋팅spring.io에서 Java-17 버전으로 선택간단한 코드 작성AppController@RestController public class AppController { @GetMapping("/") public String home() { return "Docker, World!"; } }DockerFileFROM openjdk:17-jdk COPY build/libs/*SNAPSHOT.jar app.jar ENTRYPOINT ["java", "-jar", "/app.jar"]Spring Boot 프로젝트 빌드하기 ./gradlew clean build aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin 002177417362.dkr.ecr.ap-northeast-2.amazonaws.com docker build -t instagram-server . docker tag instagram-server:latest 002177417362.dkr.ecr.ap-northeast-2.amazonaws.com/instagram-server:latest docker push 002177417362.dkr.ecr.ap-northeast-2.amazonaws.com/instagram-server:latestAWS EC2에서 AWS CLI 설치 및 액세스 키 등록하기AWS ECR로부터 이미지 다운받아 컨테이너 띄우기aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin 002177417362.dkr.ecr.ap-northeast-2.amazonaws.com docker pull 002177417362.dkr.ecr.ap-northeast-2.amazonaws.com/instagram-server docker run -d -p 8080:8080 002177417362.dkr.ecr.ap-northeast-2.amazonaws.com/instagram-server혹시나 아래와 같은 에러가 발생했다면?이 에러의 원인은 CPU 아키텍처 환경이 다르다는 뜻이다. 조금 더 자세히 설명하자면, 이미지 빌드는 M1과 같은 ARM 기반의 환경에서 진행하고, 이미지 실행은 ARM 기반의 환경이 아닌 곳에서 할 때 위와 같은 에러가 발생한다. 위 에러를 해결하기 위해서는 이미지를 실행시키고자 하는 CPU 아키텍처에 맞춰서 이미지를 빌드해야 한다. 로컬 환경에서 아래와 같이 다시 빌드한 뒤 AWS ECR로 Push하자. ./gradlew clean build aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin 002177417362.dkr.ecr.ap-northeast-2.amazonaws.com docker build --platform linux/amd64 -t instagram-server . docker tag instagram-server:latest 002177417362.dkr.ecr.ap-northeast-2.amazonaws.com/instagram-server:latest docker push 002177417362.dkr.ecr.ap-northeast-2.amazonaws.com/instagram-server:latest-- AWS EC2의 CPU 아키텍처 확인하는 방법lscpux86_64 = linux/amd64--aws 서버에 배포하기aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin 002177417362.dkr.ecr.ap-northeast-2.amazonaws.com docker pull 002177417362.dkr.ecr.ap-northeast-2.amazonaws.com docker image ls docker run -d -p 8080:8080 [이미지 이름] -- docker compose로 실행해보기compose.ymlservices: instagram-server: image: 002177417362.dkr.ecr.ap-northeast-2.amazonaws.com/instagram-server:latest ports: - 8080:8080docker compose up -d --build # 이미지 업데이트 시 docker compose pull docker compose up -d --build 잘 작동하는지 확인.docker ps docker logs [실습] AWS EC2에 Spring Boot, MySQL, Redis 배포하기compose.yml에 MySQL, Redis 관련 내용 추가하기compose.ymlservices: instagram-server: image: 002177417362.dkr.ecr.ap-northeast-2.amazonaws.com/instagram-server:latest ports: - 8080:8080 depends_on: my-db: condition: service_healthy my-cache-server: condition: service_healthy my-db: image: mysql environment: MYSQL_ROOT_PASSWORD: pwd1234 MYSQL_DATABASE: mydb volumes: - ./mysql_data:/var/lib/mysql ports: - 3306:3306 healthcheck: test: [ "CMD", "mysqladmin", "ping" ] interval: 5s retries: 10 my-cache-server: image: redis ports: - 6379:6379 healthcheck: test: [ "CMD", "redis-cli", "ping" ] interval: 5s retries: 10컨테이너 실행하기docker compose up -d --build # 잘 실행되고 있는 지 확인 docker ps docker compose ps docker compose logs

2025. 10. 10.
0
AWS EC2에 서버 배포해보기
배포란?다른 사용자들이 인터넷을 통해서 사용할 수 있게 만드는 걸 의미한다. EC2란? / EC2를 왜 배울까? / 현업에서 EC2는 주로 언제 쓸까?--> 컴퓨터를 빌려서 원격으로 접속해 사용하는 서비스 -- EC2(Elastic Compute Cloud)를 왜 배울까?서버를 배포하기 위해서는 컴퓨터가 필요하다. 내가 가진 컴퓨터에서 서버를 배포해 다른 사용자들이 인터넷을 통해 접근할 수 있게 만들 수도 있다. 하지만 내 컴퓨터로 서버를 배포하면 24시간 동안 컴퓨터를 켜놔야 한다. 그리고 인터넷을 통해 내 컴퓨터에 접근할 수 있게 만들다보니 보안적으로도 위험할 수도 있다. 이러한 불편함 때문에 내가 가지고 있는 컴퓨터를 사용하지 않고, AWS EC2라는 컴퓨터를 빌려서 사용하는 것이다. 이 외에도 AWS EC2는 여러 부가기능들(로깅, 오토스케일링, 로드밸런싱 등)을 많이 가지고 있다. -- 현업에서는?현업에서도 실제 서버를 배포할 때 AWS EC2를 아주 많이 사용한다. 백엔드 서버를 배포해야 할 때면 EC2에 서버를 배포해서 사용한다. [실습] 1. 리전(Region) 선택하기AWS EC2를 시작하기 위해서는 우선적으로 리전(Region)을 먼저 선택해야 한다.-- 리전(Region)이란?리전(Region)이란 인프라를 지리적으로 나누어 배포한 각각의 데이터 센터를 의미한다.우린 EC2가 컴퓨터를 빌려서 원격으로 접속해 사용하는 서비스라는 걸 알고 있다. 여기서 EC2를 통해 빌려서 쓸 수 있는 컴퓨터들이 전 세계적으로 다양하게 분포해있다. 이렇게 컴퓨터들이 위치한 위치를 보고 AWS에서는 리전(Region)이라고 한다.애플리케이션의 주된 사용자들의 위치와 지리적으로 가까운 리전(Region)을 선택하는 것이 유리 [실습] 2. EC2 셋팅하기 - 기본 설정이름 및 태그EC2의 이름을 설정하는 곳이다. 이름을 지을 때는 이 컴퓨터가 어떤 역할을 하는 지 알아볼 수 있게 작성한다. Application and OS Images (Amazon Machine Image)Ubuntu 22.04 LTS 선택OS를 선택하는 단계이다. OS(운영체제)란 Mac, Windows 7, Windows 10, Windows 11 같은 것들이 OS이다. 하지만 Windows나 Mac OS는 생각보다 용량도 많이 차지하고 성능도 많이 잡아먹는다. 그래서 서버를 배포할 컴퓨터의 OS는 훨씬 가벼운 Ubuntu를 많이 사용한다. 인스턴스 유형인스턴스란, AWS EC2에서 빌리는 컴퓨터 1대를 의미한다.그럼 인스턴스 유형은 무슨 뜻일까? 컴퓨터 사양을 의미한다. 컴퓨터 사양이 좋으면 좋을수록 많은 수의 요청을 처리할 수 있고, 무거운 서버나 프로그램을 돌릴 수 있다.프리 티어에 해당하는 t2.micro를 사용 키 페어(로그인)키 페어(Key Pair)는 무슨 뜻일까?EC2 컴퓨터에 접근할 때 사용하는 비밀번호라고 생각하면 된다. 말 그대로 열쇠(Key, 키)의 역할을 한다. [실습] 3. EC2 셋팅하기 - 보안그룹 설정네트워크 설정네트워크 설정 칸을 보면 VPC와 Security Groups(보안 그룹)가 보인다. 여기서 VPC라는 개념은 AWS를 입문하는 입장에서는 크게 중요하지 않으니 넘어가자. 나중에 AWS에 어느 정도 익숙해졌을 때 VPC를 학습하도록 하자. VPC를 몰라도 서버를 배포하는 데 아무 문제가 없다. 하지만 Security Groups(보안 그룹)은 서버를 배포할 때 중요한 개념이므로 자세히 알아보자. 보안 그룹(Security Group)이란?보안 그룹(Security Group)이란 AWS 클라우드에서의 네트워크 보안을 의미한다. EC2 인스턴스를 집이라고 생각한다면, 보안 그룹은 집 바깥 쪽에 쳐져있는 울타리와 대문이라고 생각하면 된다. 집에 접근할 때 울타리의 대문에서 접근해도 되는 요청인지 보안 요원이 검사를 하는 것과 비슷하다. EC2 인스턴스 주위에 방화벽 역할을 할 보안 그룹(Security Group)을 만들고 보안 그룹에 규칙을 지정한다. 이 보안 규칙에는 인바운드 트래픽(즉, 외부에서 EC2 인스턴스로 보내는 트래픽)에서 어떤 트래픽만 허용할 지 설정할 수 있고, 아웃바운드 트래픽(즉, EC2 인스턴스에서 외부로 나가는 트래픽)에서 어떤 트래픽만 허용할 지 설정할 수 있다. 보안 그룹을 설정할 때는 허용할 IP 범위와 포트(port)를 설정할 수 있다. 보안 그룹 설정외부에서 EC2로 접근할 포트는 22번 포트와 80번 포트라고 생각해서 이 2가지에 대해 인바운드 보안 그룹 규칙을 추가했다. 왜냐하면 22번 포트는 우리가 EC2에 원격 접속할 때 사용하는 포트이고, 80번 포트에는 백엔드 서버를 띄울 예정이기 때문이다. 그리고 어떤 IP에서든 전부 접근할 수 있게 만들기 위해 소스 유형은 위치 무관으로 설정했다. [실습] 4. EC2 셋팅하기 - 스토리지 구성EC2도 하나의 컴퓨터이다보니 여러 파일들을 저장할 저장 공간이 필요하다. 이 저장 공간을 보고 EBS(Elastic Block Storage)라고 부른다. 즉, EBS란 EC2 안에 부착되어 있는 일종의 하드디스크라고 생각하면 된다. EBS와 같은 저장 공간을 조금 더 포괄적인 용어로 스토리지(Storage), 볼륨(Volume)이라고 부른다. 가성비가 좋은 gp3를 선택해주자. 용량을 30GiB를 설정한 이유는 프리 티어에서 30GiB까지 무료로 제공해주기 때문이다. 이 스토리지의 크기는 추후에 늘릴 수도 있으므로 처음 설정할 때 너무 큰 고민을 할 필요는 없다. [실습] 5. EC2 접속하기생성된 인스턴스 정보 해석하기세부 정보에서 눈여겨 봐야 할 부분은 2가지 밖에 없다. 퍼블릭 IPv4 주소와 인스턴스 상태이다.퍼블릭 IPv4 주소는 EC2 인스턴스가 생성되면서 부여받은 IP 주소이다. EC2 인스턴스에 접근하려면 이 IP 주소로 접근하면 된다.인스턴스 상태는 말그대로 EC2 인스턴스가 실행 중이라는 뜻은 컴퓨터가 켜져있다는 뜻이다.EC2 인스턴스를 중지, 재부팅, 종료도 할 수 있다. 우리가 쓰는 컴퓨터와 아주 유사하다. 재부팅은 말그대로 컴퓨터를 재시작시키는 걸 의미하고, 중지는 컴퓨터를 잠시 꺼놓는 걸 의미한다. 종료는 컴퓨터를 아예 삭제시킨다는 걸 의미한다.EC2 인스턴스를 한 번 종료하면 도중에 취소할 수 없으니 조심해야 한다. 보안(보안 그룹)인스턴스 생성 시 설정한 보안 그룹에 대한 정보가 나온다. 네트워크퍼블릭 IPv4 주소는 생성한 EC2 인스턴스의 IP 주소를 뜻한다. 스토리지인스턴스 생성 시 설정한 스토리지에 대한 정보가 나온다. 모니터링EC2 인스턴스에 관련한 여러가지 정보를 볼 수 있는 창이다. AWS를 처음 입문할 때는 자주 볼 일이 없는 창이지만, 나중에 실제 서버를 운영할 때는 자주 보게되는 창이다. EC2 인스턴스가 정상적으로 작동하고 있는 지, EC2 인스턴스의 성능을 향상시켜주어야 하는 건 아닌 지 아래 지표를 통해 파악할 수 있다. [실습] 6. 탄력적 IP 연결하기EC2 인스턴스를 생성하면 IP를 할당받는다. 하지만 이렇게 할당받은 IP는 임시적인 IP이다. EC2 인스턴스를 잠깐 중지시켰다가 다시 실행시켜보면 IP가 바뀌어있다. EC2 인스턴스를 중지시켰다가 다시 실행시킬 때마다 IP가 바뀌면 굉장히 불편하다. 그래서 중지시켰다가 다시 실행시켜도 바뀌지 않는 고정 IP를 할당받아야 한다. 현업에서도 EC2 인스턴스를 생성하면 탄력적 IP를 대부분 필수적으로 설정한다. [실습] 7. Express 서버를 EC2에 배포하기Ubuntu 환경에서 Node.js 설치하는 법Ubuntu 환경에서 Express 서버를 실행시키려면 Node.js가 설치되어 있어야 한다. 그래서 Ubuntu에 우선 Node.js를 설치해보자.sudo su apt-get update && / apt-get install -y ca-certificates curl gnupg && / mkdir -p /etc/apt/keyrings && / curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg && / NODE_MAJOR=20 && / echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list && / apt-get update && / apt-get install nodejs -y 잘 설치됬는지 확인node -v github로 Express 프로젝트 clone하기 git clone https://github.com/JSCODE-EDU/ec2-express-sample cd ec2-express-sample npm i .env파일 직접 만들기.env와 같은 민감한 파일은 Git으로 버전 관리를 하지 않는게 일반적이다. 따라서 .env 파일은 별도로 EC2 인스턴스에 올려주어야 한다. 하지만 .env 파일을 EC2 인스턴스에 올리는 작업보다는, .env 파일을 직접 만드는 게 훨씬 간단하다..envDATABASE_NAME=my_databasepm2 설치해서 서버 실행시키기Node 기반의 서버는 pm2를 활용해서 많이 실행시킨다. 서비스를 운영하는 데 있어서 유용한 기능들을 pm2가 많이 가지고 있기 때문이다. sudo npm i -g pm2 sudo pm2 start app.js잘 작동되는지 확인 pm2 정지하기# pm2로 실행중인 프로젝트에 대한 앱 이름 확인 sudo pm2 list # sudo pm2 stop [앱 이름] sudo pm2 stop app Spring Boot 서버를 EC2에 배포하기Ubuntu 환경에서 JDK 설치하는 법sudo apt update && / sudo apt install openjdk-17-jdk -y잘 설치 됬는지 확인java -versionGithub로부터 Spring Boot 프로젝트 clone 하기git clone https://github.com/JSCODE-EDU/ec2-spring-boot-sample.git cd ec2-spring-boot-sampleapplication.yml 파일 직접 만들기application.yml와 같은 민감한 정보가 포함된 파일은 Git으로 버전 관리를 하지 않는게 일반적이다. 따라서 application.yml 파일은 별도로 EC2 인스턴스에 올려주어야 한다. 하지만 application.yml 파일을 EC2 인스턴스에 올리는 작업보다는, application.yml 파일을 직접 만드는 게 훨씬 간단하다.src/main/resources/application.ymlserver: port: 80서버 실행하기 ./gradlew clean build # 기존 빌드된 파일을 삭제하고 새롭게 JAR로 빌드 cd ~/ec2-spring-boot-sample/build/libs sudo java -jar ec2-spring-boot-sample-0.0.1-SNAPSHOT.jar참고) 백그라운드에서 Spring Boot 실행하기sudo nohup java -jar ec2-spring-boot-sample-0.0.1-SNAPSHOT.jar & 잘 작동되는 지 확인. 비용 나가지 않게 EC2 깔끔하게 종료하기EC2 인스턴스 종료하기탄력적 IP 릴리스하기

2025. 10. 09.
0
Docker Compose를 활용해 2개 이상의 컨테이너 관리하기
[실습] MySQL, Redis 컨테이너 동시에 띄워보기Docker Compose로 MySQL, Redis 실행시키기compose.ymlservices: my-db: image: mysql environment: MYSQL_ROOT_PASSWORD: pwd1234 volumes: - ./mysql_data:/var/lib/mysql ports: - 3306:3306 my-cache-server: image: redis ports: - 6379:6379 compose 파일 실행 및 삭제docker compose up -d docker compose ps docker compose down [실습] Spring Boot, MySQL 컨테이너 동시에 띄워보기application.ymlspring: datasource: url: jdbc:mysql://localhost:3306/mydb username: root password: pwd1234 driver-class-name: com.mysql.cj.jdbc.DriverDockerfileFROM openjdk:17-jdk COPY build/libs/*SNAPSHOT.jar /app.jar ENTRYPOINT ["java", "-jar", "/app.jar"]compose.ymlservices: my-server: build: . ports: - 8080:8080 # my-db의 컨테이너가 생성되고 healthy 하다고 판단 될 때, 해당 컨테이너를 생성한다. depends_on: my-db: condition: service_healthy my-db: image: mysql environment: MYSQL_ROOT_PASSWORD: pwd1234 MYSQL_DATABASE: mydb # MySQL 최초 실행 시 mydb라는 데이터베이스를 생성해준다. volumes: - ./mysql_data:/var/lib/mysql ports: - 3306:3306 healthcheck: test: [ "CMD", "mysqladmin", "ping" ] # MySQL이 healthy 한 지 판단할 수 있는 명령어 interval: 5s # 5초 간격으로 체크 retries: 10 # 10번까지 재시도Spring Boot 프로젝트 빌드 및 compose 파일 실행./gradlew clean build docker compose up -d --buildcompose 실행 현황 보기docker compose ps docker logs [Container ID]Spring Boot 컨테이너의 로그를 열어보면 아래와 같이 에러 메시지가 떠있다. 아래 에러 메시지는 DB와 연결이 제대로 이루어지지 않았을 때 발생하는 에러이다.MySQL이 정상적으로 실행이 안 되고 있는 건지 확인하기 위해 DB GUI 툴(ex. Workbench, Datagrip, DBeaver 등)을 활용해 DB 연결을 해보자. MySQL에 연결을 시도해보면 정상적으로 연결이 잘 되는 걸 확인할 수 있다. 컨테이너로 실행시킨 Spring Boot가 MySQL에 연결이 안 되는 이유각각의 컨테이너는 자신만의 네트워크망과 IP 주소를 가지고 있다. 호스트 컴퓨터 입장에서 localhost는 호스트 컴퓨터를 가리키지만, Spring Boot 컨테이너 입장에서 localhost는 Spring Boot 컨테이너를 가리킨다. 그런데 Spring Boot의 코드를 작성할 때 DB 정보를 아래와 같이 입력했었다. Spring Boot가 실행되는 환경인 컨테이너 입장에서 localhost:3306라는 주소는, Spring Boot 컨테이너 내부에 있는 3306번 포트와 연결을 시도하게 된다. 하지만 Spirng Boot가 실행되는 컨테이너 내부의 3306번 포트에는 아무것도 실행되고 있지 않다. 이러한 구조상의 문제 때문에 Spring Boot가 MySQL에 연결이 안 되고 있었던 것이다. application.ymlspring: datasource: url: jdbc:mysql://localhost:3306/mydb username: root password: pwd1234 driver-class-name: com.mysql.cj.jdbc.Driver-- compose.yml에서 정의한 Service 이름으로 서로 통신할 수 있다. 바로 예시로 알아보자. Spring Boot의 DB 정보를 아래와 같이 수정한 뒤 시도해보기application.ymlspring: datasource: url: jdbc:mysql://my-db:3306/mydb username: root password: pwd1234 driver-class-name: com.mysql.cj.jdbc.Driver 이전에 작성했던 compose.yml을 보면 각 컨테이너에 service 이름(my-server, my-db)을 작성했었다. compose.ymlservices: my-server: build: . ports: - 8080:8080 depends_on: my-db: condition: service_healthy my-db: image: mysql environment: MYSQL_ROOT_PASSWORD: pwd1234 MYSQL_DATABASE: mydb volumes: - ./mysql_data:/var/lib/mysql ports: - 3306:3306 healthcheck: test: [ "CMD", "mysqladmin", "ping" ] interval: 5s retries: 10이 service 이름이 컨테이너의 주소를 뜻한다. 해당 컨테이너의 IP 주소와 같은 역할을 한다. 위와 같이 코드를 수정한 뒤에 다시 한 번 컨테이너를 실행시켜보자. ./gradlew clean build docker compose down docker compose up --build -d docker ps # 정상적으로 Spring Boot, MySQL이 실행된 걸 확인할 수 있다. [실습] Spring Boot, MySQL, Redis 컨테이너 동시에 띄워보기Spring Boot 프로젝트에 Redis 연결 코드 추가하기build.gradle... dependencies { ... implementation 'org.springframework.boot:spring-boot-starter-data-redis' } application.ymlspring: datasource: url: jdbc:mysql://my-db:3306/mydb username: root password: pwd1234 driver-class-name: com.mysql.cj.jdbc.Driver data: redis: host: localhost port: 6379RedisConfig@Configuration public class RedisConfig { @Bean public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) { RedisTemplate template = new RedisTemplate(); template.setConnectionFactory(connectionFactory); template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); return template; } }AppController@RestController public class AppController { @Autowired private RedisTemplate redisTemplate; @GetMapping("/") public String home() { redisTemplate.opsForValue().set("abc", "def"); return "Hello, World!"; } }compose.ymlservices: my-server: build: . ports: - 8080:8080 depends_on: my-db: condition: service_healthy my-cache-server: condition: service_healthy my-db: image: mysql environment: MYSQL_ROOT_PASSWORD: pwd1234 MYSQL_DATABASE: mydb volumes: - ./mysql_data:/var/lib/mysql ports: - 3306:3306 healthcheck: test: [ "CMD", "mysqladmin", "ping" ] interval: 5s retries: 10 my-cache-server: image: redis ports: - 6379:6379 healthcheck: test: [ "CMD", "redis-cli", "ping" ] interval: 5s retries: 10Docker 컨테이너로 띄워보기 ./gradlew clean build docker compose down docker compose up --build -d위 명령어를 통해 컨테이너를 띄운 뒤에 localhost:8080으로 요청을 해보면 아래와 같은 에러가 발생한다.connection refused에러가 발생한 이유는 Redis와 연결이 잘 안 됐기 때문이다. 왜 안됐는 지application.yml파일을 확인 application.ymlspring: datasource: url: jdbc:mysql://my-db:3306/mydb username: root password: pwd1234 driver-class-name: com.mysql.cj.jdbc.Driver data: redis: host: my-cache-server port: 6379각 컨테이너는 각자의 네트워크를 가지고 있기 때문에, localhost가 아니라 Redis가 실행되고 있는 컨테이너로 통신을 해야 한다. Redis가 실행되고 있는 컨테이너의 주소는 service 이름으로 표현한다고 했다. compose.yml에서 Redis가 실행되고 있는 컨테이너의 service 이름을 my-cache-server라고 이름 붙였다. 다시 실행 ./gradlew clean build docker compose down docker compose up --build -d

2025. 10. 09.
0
Docker Compose를 활용해 컨테이너 관리하기
Docker Compose를 사용하는 이유Docker Compose란?여러 개의 Docker 컨테이너들을 하나의 서비스로 정의하고 구성해 하나의 묶음으로 관리할 수 있게 도와주는 툴. Docker Compose를 사용하는 이유여러 개의 컨테이너를 관리하는 데 용이복잡한 명령어로 실행시키던 걸 간소화 시킬 수 있음[실습] Docker Compose 전체 흐름 느껴보기 (Nginx 설치 및 실행)Docker CLI로 컨테이너를 실행시킬 때docker run --name webserver -d -p 80:80 nginxDocker Compose로 컨테이너를 실행시킬 때compose.yml 파일 작성하기.services: my-web-server: container_name: webserver image: nginx ports: - 80:80services: my-web-sever: Docekr Compose에서 하나의 컨테이너를 서비스(service)라고 부른다. 이 옵션은 서비스에 이름을 붙이는 기능이다.container_name: webserver컨테이너를 띄울 때 붙이는 별칭이다. CLI에서 --name web-werver역할과 동일하다.image: nginx컨테이너를 실행시킬 때 어떤 이미지를 사용할 지 정의하는 명령어이다. docker run [이미지명]와 동일한 역할이다.ports: 포트 매핑은 어떻게 할 지를 설정하는 옵션이다. CLI에서 -p 80:80역할과 동일하다.compose 파일 실행시키기docker compose up -dcompose 실행 현황 보기docker compose pscompose로 실행된 컨테이너 삭제docker compose down자주 사용하는 Docker Compose CLI 명령어compose 파일 작성services: websever: container_name: webserver image: nginx ports: - 80:80compose.yml에서 정의한 컨테이너 실행docker compose up # 포그라운드에서 실행 docker compose up -d # 백그라운드에서 실행-d: 백그라운드에서 실행Docker Compose로 실행시킨 컨테이너 확인하기# compose.yml에 정의된 컨테이너 중 실행 중인 컨테이너만 보여준다. docker compose ps # compose.yml에 정의된 모든 컨테이너를 보여준다. docker compose ps -aDocker Compose 로그 확인하기# compose.yml에 정의된 모든 컨테이너의 로그를 모아서 출력한다. docker compose logs컨테이너를 실행하기 전에 이미지 재빌드하기 docker compose up --build # 포그라운드에서 실행 docker compose up --build -d # 백그라운드에서 실행compose.yml에서 정의한 이미지 파일에서 코드가 변경 됐을 경우, 이미지를 다시 빌드해서 컨테이너를 실행시켜야 코드 변경된 부분이 적용된다. 그러므로 이럴 때에는 --build옵션을 추가해서 사용해야 한다. 참고: docker compose upvs docker compose up --build -- docker compose up: 이미지가 없을 때만 빌드해서 컨테이너를 실행시킨다. 이미지가 이미 존재하는 경우 이미지를 빌드하지 않고 컨테이너를 실행시킨다. -- docker compose up --build : 이미지가 있건 없건 무조건 빌드를 다시해서 컨테이너를 실행시킨다. 이미지 다운받기 / 업데이트하기docker compose pullcompose.yml에서 정의된 이미지를 다운 받거나 업데이트 한다.로컬 환경에 이미지가 없다면 이미지를 다운 받는다.로컬 환경에 이미 이미지가 있는데, Dockerhub의 이미지와 다른 이미지일 경우 이미지를 업데이트 한다.Docker Compose에서 이용한 컨테이너 종료하기docker compose down[실습] Docker Compose로 Redis 실행시키기compose.ymlservices: my-cache-server: image: redis ports: - 6379:6379 compose 파일 실행 및 확인docker compose up -d docker compose ps docker logs [컨테이너 ID 또는 컨테이너명] docker exec -it [컨테이너 ID 또는 컨테이너명] bash redis-cli 127.0.0.1:6379> set 1 jscode 127.0.0.1:6379> get 1 docker compose down[실습] Docker Compose로 MySQL 실행시키기compose.ymlservices: my-db: image: mysql environment: # -e MYSQL_ROOT_PASSWORD=password 역할 MYSQL_ROOT_PASSWORD: pwd1234 volumes:# v {호스트 경로}:/var/lib/mysql 역할 - ./mysql_data:/var/lib/mysql ports: - 3306:3306environment: ...:CLI에서 -e MYSQL_ROOT_PASSWORD=password 역할과 동일하다.volumes: ...:CLI에서 -v {호스트 경로}:/var/lib/mysql 역할과 동일하다.compose 파일 실행 및 확인docker compose up -d docker compose ps docker compose down[실습] Docker Compose로 백엔드(Spring Boot) 실행시키기AppController@RestController public class AppController { @GetMapping("/") public String home() { return "Hello, World!"; } }DockerfileFROM openjdk:17-jdk COPY build/libs/*SNAPSHOT.jar /app.jar ENTRYPOINT ["java", "-jar", "/app.jar"]Spring Boot 프로젝트 빌드./gradlew clean buildcompose.ymlservices: my-server: #compose.yml이 존재하는 디렉토리(.)에 있는 Dockerfile로 이미지를 생성 build: . ports: - 8080:8080build: .:compose.yml이 존재하는 디렉토리(.)에 있는 Dockerfile로 이미지를 생성해 컨테이너를 띄우겠다는 의미이다.compose 파일 실행 및 확인docker compose up -d --build docker compose ps docker compose down[실습] Docker Compose로 백엔드(Nest.js) 실행시키기Next.js 프로젝트 만들기# Nest CLI 설치 npm i -g @nestjs/cli # nest new {프로젝트명} nest new my-serverDockerfileFROM node WORKDIR /app COPY . . RUN npm install RUN npm run build EXPOSE 3000 ENTRYPOINT [ "node", "dist/main.js" ].dockerignorenode_modulescompose.ymlservices: my-server: build: . ports: - 3000:3000compose 파일 실행 및 확인docker compose up -d --build docker compose ps docker compose down[실습] Docker Compose로 프론트엔드(Next.js) 실행시키기Next.js 프로젝트 만들기npx create-next-app@latestDockerfileFROM node:20-alpine WORKDIR /app COPY . . RUN npm install RUN npm run build EXPOSE 3000 ENTRYPOINT [ "npm", "run", "start" ].dockerignorenode_modulescompose.ymlservices: my-web-server: build: . ports: - 80:3000compose 파일 실행 및 확인docker compose up -d --build docker compose ps docker compose down[실습] Docker Compose로 프론트엔드(HTML, CSS, Nginx) 실행시키기HTML, CSS 파일 만들기index.html My Web Page style.css* { color: blue; }DockerfileFROM nginx COPY ./ /usr/share/nginx/htmlcompose.ymlservices: my-web-server: build: . ports: - 80:80compose 파일 실행 및 확인docker compose up -d --build docker compose ps docker compose down

2025. 10. 05.
0
Dockerfile 활용해 이미지 직접 만들기
Dockerfile이란?Docker 이미지를 만들게 해주는 파일. FROM : 베이스 이미지 생성FROM은 베이스 이미지를 생성하는 역할을 한다.Docker 컨테이너를 특정 초기 이미지를 기반으로 추가적인 셋팅을 할 수 있다.여기서 예기한 '특정 초기 이미지'가 곧 베이스 이미지이다. 사용법# 문법 FROM [이미지명] FROM [이미지명]:[태그명] [실습] FROM : 베이스 이미지 생성Dockerfile 만들기# JDK 17 FROM openjdk:17-jdkDockerfile을 기반으로 이미지 만들기docker build -t my-jdk17-server .이미지를 기반으로 컨테이너 띄우기docker run -d my-jdk17-server컨테이너 조회하기docker ps # 실행되고 있는 컨테이너가 없다. docker ps -a # 확인해보니 컨테이너가 종료되어 있다. Docker의 컨테이너는 내부적으로 필요한 명령을 다 수행하면 컨테이너가 저절로 종료된다.컨테이너 내부로 들어가서 jdk가 잘 깔렸는지 확인해보기종료된 컨테이너에 들어가서 디버깅하고 싶을때FROM openjdk:17-jdk ENTRYPOINT ["/bin/bash", "-c", "sleep 500"] # 500초 동안 시스템을 일시정지 시키는 명령어docker build -t my-jdk17-server . # 이미지 빌드 docker run -d my-jdk17-server # 컨테이너 실행 docker ps # 실행 중인 컨테이너 조회 docker exec -it [컨테이너 ID] bash # 컨테이너 접속 java -version # JDK 설치되어 있는 지 확인 COPY : 파일 복사( 이동 )# 문법 COPY [호스트 컴퓨터에 있는 복사할 파일의 경로] [컨테이너에서 파일이 위치할 경로] # 예시 COPY app.txt /app.txt -- 와일드 카드 사용해보기FROM ubuntu COPY *.txt /text-files/ ENTRYPOINT ["/bin/bash", "-c", "sleep 500"] # 디버깅용 코드 -- .dockerignore 사용해보기.dockerignorereadme.txt DockerfileFROM ubuntu COPY ./ / ENTRYPOINT ["/bin/bash", "-c", "sleep 500"] # 디버깅용 코드--> readme.txt만 복사가 안된다. ENTRYPOINT : 컨테이너가 시작할때 실행되는 명령어# 문법 ENTRYPOINT [명령문...] # 예시 ENTRYPOINT ["node", "dist/main.js"]예제FROM ubuntu ENTRYPOINT ["/bin/bash", "-c", "echo hello"] docker build -t my-server . docker run -d my-server docker ps -a docker logs [Container ID] [실습] 백엔드 프로젝트(Spring Boot) 를 Docker로 실행시키기AppController@RestController public class AppController { @GetMapping("/") public String home() { return "Hello, World!"; } }DockerfileFROM openjdk:17-jdk COPY build/libs/*SNAPSHOT.jar app.jar ENTRYPOINT ["java", "-jar", "/app.jar"]# Spring Boot 프로젝트 빌드하기 ./gradlew clean build # Dockerfile을 바탕으로 이미지 빌드하기 docker build -t hello-server . # 이미지가 잘 생성됐는 지 확인하기 docker image ls # 생성한 이미지를 컨테이너로 실행시켜보기 docker run -d -p 8080:8080 hello-server # 컨테이너 잘 실행되고 있는 지 확인하기 docker ps RUN: 이미지를 생성하는 과정에서 사용할 명령문 실행RUN 은 이미지 생성 과정에서 명령어를 실행시켜야 할 때 사용한다.# 문법 RUN [명령문] # 예시 RUN npm install RUN 과 ENTRYPOINTRUN은 '이미지 생성 과정'에서 필요한 명령어를 실행시킬 때 사용하고,ENTRYPOINT는 생성된 이미지를 기반으로 컨테이너를 생성한 직후에 명령어를 실행시킬 때 사용한다. [예제]미니 컴퓨터 환경이 ubuntu로 구성되었으면 좋겠고 git이 깔려있으면 좋겠다고 가정하자. 이런 환경을 구성하기 위해 Dockerfile 을 활용해 ubuntu, git이 깔려있는 이미지를 만들면 된다. DockerfileFROM ubuntu RUN apt update && apt install -y git ENTRYPOINT ["/bin/bash", "-c", "sleep 500"]이미지 빌드 및 컨테이너 실행docker build -t my-server . docker run -d my-server docker exec -it [Container ID] bash git -v # 컨테이너 내에 git이 잘 설치됐는 지 확인 WORKDIR : 작업 디렉토리를 지정작업 디렉토리를 지정해주는 이유는 컨테이너 내부의 폴더를 깔끔하게 관리하기 위해서이며컨테이너도 미니 컴퓨터와 같기 때문에 Dockerfile을 통해 생성되는 파일들을 특정 폴더에 정리해두는 것이 추후에 관리가 쉽다.만약에 WORKDIR을 쓰지 않으면 내부에 존재하는 기존 파일들과 뒤섞여버린다. # 문법 WORKDIR [작업 디렉토리로 사용할 절대 경로] # 예시 WORKDIR /usr/src/app 예제app.txt, src, config.json 파일 만들기Dockerfile 만들어서 이미지 생성 및 컨테이너 실행 - - WORKDIR 을 안 썼을 때 파일이 어떻게 구성되는 지 먼저 확인 DockerfileFROM ubuntu COPY ./ ./ ENTRYPOINT ["/bin/bash", "-c", "sleep 500"] # 디버깅용 코드 docker build -t my-server . docker run -d my-server docker exec -it [Container ID] bash ls -- WORKDIR 을 썼을 때 파일이 어떻게 구성되는 지 확인 DockerfileFROM ubuntu WORKDIR /my-dir COPY ./ ./ ENTRYPOINT ["/bin/bash", "-c", "sleep 500"] docker build -t my-server . docker run -d my-server docker exec -it [Container ID] bash ls EXPOSE : 컨테이너 내부에서 사용 중인 포트를 문서화EXPOSE 는 컨테이너 내부에서 어떤 포트에 프로그램이 실행되는 지를 문서화하는 역할만 한다. # 문법 EXPOSE [포트 번호] # 예시 EXPOSE 3000 [실습]백엔드 프로젝트(Next.js)를 Docker로 실행Next.js 프로젝트 만들기# Nest CLI 설치 npm i -g @nestjs/cli # nest new {프로젝트명} nest new my-serverDockerfile 작성FROM node WORKDIR /app COPY . . RUN npm install RUN npm run build EXPOSE 3000 ENTRYPOINT [ "node", "dist/main.js" ].dockerignore 작성node_modulesDockerfile을 바탕으로 이미지 빌드 및 컨테이너 실행docker build -t my-server . docker image ls docker run -d -p 3000:3000 my-server docker ps 웹 프론트엔드 프로젝트(Next.js)를 Docker로 배포하기Next.js 프로젝트 만들기npx create-next-app@latestDockerfile 작성하기FROM node:20-alpine WORKDIR /app COPY . . RUN npm install RUN npm run build EXPOSE 3000 ENTRYPOINT [ "npm", "run", "start" ].dockerignore 작성node_modulesDockerfile로 이미지 빌드 및 컨테이너 실행docker build -t my-web-server . docker image ls docker run -d -p 80:3000 my-web-server docker ps 웹 프론트엔드 프로젝트(HTML, css, Nginx)를 Docker로 배포하기HTML, css 파일 만들기index.html My Web Page 주의) Nginx의 기본 설정에 의하면 메인 페이지(첫 페이지)의 파일명을 index.html 이라고 지어야 한다.style.css* { color: blue; }Dockerfile 작성FROM nginx COPY ./ /usr/share/nginx/htmlDockerfile로 이미지 빌드 및 컨테이너 실행docker build -t my-web-server . docker image ls docker run -d -p 80:80 my-web-server docker ps
![[실습] Docker로 Mysql 실행시켜보기](https://cdn.inflearn.com/public/main/blog/default_thumbnail.png?w=260)
2025. 10. 04.
0
[실습] Docker로 Mysql 실행시켜보기
Mysql 이미지를 바탕으로 컨테이너 실행 docker run -e MYSQL_ROOT_PASSWORD=password123 -p 3306:3306 -d mysql컨테이너에 들어가 환경변수 설정이 잘 되었는지 확인docker exec -it [MYSQL 컨테이너 ID] bash echo $MYSQL_ROOT_PASSWORD # MYSQL_ROOT_PASSWORD 라는 환경변수 값 출력 export # 설정되어있는 모든 환경변수 출력 Dbeaver로 연결 확인하기 window 환경의 경우 useSSL=false, allowPublicKeyRetrieval=true 설정해야 연결된다 Docker 볼륨(Volume)을 활용해 MySQL 컨테이너 띄우기MySQL 컨테이너 띄우기Docker Volumecd /Users/LeeHwiro mkdir docker-mysql # MySQL 데이터를 저장하고 싶은 폴더 만들기 # docker -run -e MYSQL_ROOT_PASSWORD=password123 -p 3306:3306 -v {호스트의 절대경로}/mysql-data:/var/lib/mysql -d mysql docker -run -e MYSQL_ROOT_PASSWORD=password123 -p 3306:3306 -v "C:/Users/LeeHwiro/docker-mysql/mysql-data:/var/lib/mysql" -d mysql MySQL 컨테이너 삭제하고 다시 띄워보기#컨테이너 종료 docker stop [MYSQL 컨테이너 ID] docker rm [MYSQL 컨테이너 ID] # 비밀번호 바꿔서 컨테이너 생성 docker -run -e MYSQL_ROOT_PASSWORD=pwd123 -p 3306:3306 -v "C:/Users/LeeHwiro/docker-mysql/mysql-data:/var/lib/mysql" -d mysql docker exec -it [MySQL 컨테이너 ID] bash mysql -u root -p # 접속이 안됨 해결 방법 : 기존 Volume 파일을 제거 후 다시 컨테이너를 생성시킨다. Docker Volume을 활용해 postGresql 띄우기docker run -e POSTGRES_PASSWORD=password123 -p 5432:5432 -v "C:/Users/LeeHwiro/docker-postgresql/postgresql_data:/var/lib/postgresql" -d postgres Docker Volume을 활용해 mongoDB 띄우기docker run -e MONGO_INITDB_ROOT_USERNAME=root -e MONGO_INITDB_ROOT_PASSWORD=password123 -p 27017:27017 -v "C:\Users\LeeHwiro\docker-mongodb/mongodb_data:/data/db" -d mongo

2025. 10. 03.
0
Docker Volume(도커 볼륨) 이란?
Docker Volume(도커 볼륨) 이란?도커의 볼륨(Volume)이란 도커 컨테이너에서 영속적으로 저장하기 위한 방법이다.볼륨(Volume)은 컨테이너 자체의 저장 공간을 사용하지 않고, 호스트 자체의 저장 공간을 공유해서 사용하는 형태이다.볼륨을 사용하는 명령어$ docker run -v [호스트의 디렉토리 절대경로]:[컨테이너의 디렉토리 절대경로] [이미지명]:[태그명]-- [호스트의 디렉토리 절대 경로] 에 디렉토리가 이미 존재할 경우, 호스트의 디렉터리가 컨테이너의 디렉터리를 덮어씌운다.-- [호스트의 디렉토리 절대 경로] 에 디렉토리가 존재하지 않을 경우, 호스트의 디렉터리 절대 경로에 디렉터리를 새로 만들고 컨테이너의 디렉터리에 있는 파일들을 호스트의 디렉터리로 복사해온다.
개발 · 프로그래밍 기타
・
Docker




