역경으로 시작한 아침..
코드카타 하는데 인텔리제이만 너무 버벅대서 50분 정도를 이것저것 설정 건드려보느라 날렸다
보조모니터 때문인가, 뭐 다른게 실행되고 있나.. 재부팅도 해보고 별걸 다했는데
충전 꽂으니까 말짱해졌다 ㅋ ㅋ ㅋ ㅋ ㅋ
다중 컨테이너 애플리케이션을 정의하고 실행하기 위한 도구
단일 파일(docker-compose.yml)에 여러 컨테이너의 설정을 정의하여 컨테이너 간의 의존성, 네트워크, 볼륨 공유 등을 편하게 관리할 수 있다
여러 서비스를 한번에 실행, 중지, 재시작할 수 있는 도구.
| 명령어 | 설명 |
|---|---|
docker compose up | 모든 서비스 컨테이너를 생성 및 실행 |
docker compose up -d | 컨테이너를 백그라운드에서 실행 |
docker compose down | 실행 중인 컨테이너를 중지 및 네트워크, 볼륨 삭제 |
docker compose ps | 실행 중인 컨테이너 목록 확인 |
docker compose logs | 모든 서비스의 로그 확인 |
docker compose logs -f | 실시간 로그를 확인 |
docker compose restart | 모든 컨테이너를 재시작 |
docker compose build | 이미지를 새로 빌드 |
장점
1. 개발 환경 설정 간소화: 여러 컨테이너를 한 번에 설정하고 실행 가능
2. 환경 간 일관성: 동일한 설정 파일로 개발, 테스트, 프로덕션 환경을 구성
3. 의존성 관리: 서비스 간의 의존 관계를 명확히 정의하고 관리
4. 간편한 유지보수: YAML 파일을 수정하여 손쉽게 서비스 업데이트 가능
단점
1. 복잡성 증가: 프로젝트 규모에 맞게 선택해야 할 필요가 있다
2. 확장성 부족: 대규모 시스템에서는 Kubernetes와 같은 오케스트레이션 도구가 더 적합할 수 있음
| 항목 | Docker Compose | Kubernetes |
|---|---|---|
| 목적 | 다중 컨테이너 애플리케이션의 로컬 환경 설정 및 실행 | 컨테이너의 대규모 배포, 스케일링, 관리 |
| 복잡성 | 간단하며, 소규모 프로젝트에 적합 | 복잡하지만 대규모 분산 환경에 적합 |
| 확장성 | 제한적 (로컬 개발 환경 중심) | 자동 확장 및 고가용성 지원 |
| 운영 환경 | 주로 개발 및 테스트 환경 | 프로덕션 환경에 최적화 |
| 네트워크 | 기본적으로 프로젝트별 네트워크 생성 | 다양한 네트워크 옵션과 컨트롤 제공 |
Docker container 간 통신을 설정하고 관리하기 위한 기능
네트워크를 통해 컨테이너 간 데이터 교환, 외부 네트워크와의 연결, 보안 설정 등을 제어할 수 있음
Docker는 컨테이너의 기본 네트워크 설정을 제공하며, 필요에 따라 사용자 정의 네트워크를 생성하고 구성할 수도 있다
Docker에서 컨테이너는 격리된 네트워크 환경에서 실행되며, 컨테이너의 내부 포트와 호스트 포트를 매핑하여 통신함
같은 컨테이너 포트 번호라도 다른 호스트 포트에 연결하면 문제 없이 실행 가능
컨테이너 내부 포트 (Container Port)
호스트 포트 (Host Port)
포트 매핑 구조
docker run -d -p 8080:80 nginx
docker run -d -p 8081:80 nginx-p <컨테이너 포트> 형식으로 작성하면 Docker가 사용 가능한 호스트 포트를 자동 할당해줌docker run -d -p 80 nginx
+포트 번호는 `docker ps`나 `docker inspect` 명령어로 확인할 수 있다
### Docker 네트워크 모드에 따른 포트 매핑 차이
1. Bridge 네트워크(기본)
- 컨테이너는 자체 IP 주소를 사용하며, 포트 매핑을 통해 호스트와 통신함
- 외부에서 접근하려면 -p 옵션을 사용해 포트를 노출
2. Host 네트워크
- 컨테이너가 호스트의 네트워크 스택을 공유
- 포트 매핑 없이 컨테이너 포트가 호스트 포트에 직접 연결함
```docker run --network host nginx```
3. None 네트워크
- 컨테이너가 네트워크를 비활성화하며, 외부 통신이 불가함
## 해보자!
### 1. Docker를 이용해 컨테이너 간 통신
- service A, B 컨테이너 생성
- service A 컨테이너로 호출 -> service B 호출 -> 응답 반환
1. Service A, B를 생성하고 각각 기본 설정과 컨트롤러 작성을 진행
- service A
```java
@RestController
@AllArgsConstructor
public class AController {
private final BServiceClient bServiceClient;
@GetMapping("/hi")
public String hi() {
String messageB = bServiceClient.getHello();
return "service-a : hi~ service-b : " + messageB;
}
}
@RestController
public class BController {
@GetMapping("/hello")
public String hello() {
return "Hello from B~";
}
}
service A의 "/hi"로 요청을 보내면, Feign Client를 통해 B service에 요청을 보내고, "/hello" 경로의 응답을 가져올 것이다.

요러케.
A는 18080, B는 18081 포트로 실행중이다.
정상 실행되는 것을 확인하고, 컨테이너 간의 통신을 시도해본다.
어차피 다른 환경에서 돌아가기 때문에 포트번호도 일치시켜주고, 각 서비스에 Dockerfile을 생성했다.
FROM openjdk:17-jdk-slim
VOLUME /tmp
ARG JAR_FILE=build/libs/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
서로를 이름으로 호출하기 위해 사용자 정의 네트워크를 만들 것이다.
docker network create my-network
Is the docker daemon running? -> open -a Docker 로 Docker 실행

네트워크가 정상 생성 되었다.
각각의 서비스 프로젝트를 빌드하고 각각의 이미지를 생성한다.
docker build -t img-service-a .
docker build: Docker 이미지 생성
-t img-serevice-a
-t: Tag. 생성된 이미지에 이름을 부여함img-service-a: 생성될 이미지의 이름(tag)name:tag 형식으로 지정할 수 있으며, 기본적으로 latest 태그가 사용된다(ex: img-service-a:1.0).
생성된 이미지는 docker images 명령어로 확인 가능



같은 방법으로 service A도 띄워준다

정상적으로 컨테이너가 띄워진 걸 확인하고, 아까와 같은 방법으로 호출해본다.

정상적으로 응답이 반환되는 것을 확인할 수 있다.

일단 실행중인 컨테이너를 내리고, docker -rm 으로 컨테이너를 지웠다.
version: '3.8'
services:
service-a:
image: img-service-a
ports:
- "18080:8080"
environment:
- SERVICE_B_URL=http://service-b:8080
depends_on:
- service-b
service-b:
image: img-service-b
ports:
- "18081:8080"
networks:
default:
driver: bridge

실행하면 포함된 서비스(여기선 2개)의 실행 로그가 막 섞여 뜬다.

정상 실행 중임을 확인

요청을 보내면 응답이 정상 반환됨을 알 수 있다. 와!
+docker compose는 실행될 때 새로운 네트워크를 만들어 포함된 서비스들을 한 네트워크 내에서 실행한다.

위의 docker compose 내 서비스들은 docker_prac_default 라는 새로운 브리지 네트워크에서 실행된 것.
Continuous Integration(지속적 통합)
Continuous Delivery/Deployment (지속적 배포/전개)
소프트웨어 개발에서 자동화된 프로세스로 코드를 빠르고 신뢰성 있게 빌드, 테스트, 배포하는 방법론
코드 변경사항이 애플리케이션에 통합되고 사용자에게 제공되는 속도와 품질을 향상시킬 수 있음
목표
주요 단계
1. Push: 개발자가 코드 변경사항을 리포에 올림
2. 자동 빌드: push된 코드로 애플리케이션을 빌드
3. 자동화 테스트: 빌드된 애플리케이션에 대해 유닛 테스트, 통합 테스트 등 실행
Continuous Delivery (지속적 배포)
Continuous Deployment (지속적 전개)
| 항목 | Continuous Delivery | Continuous Deployment |
|---|---|---|
| 배포방식 | 자동화된 배포 준비+수동 승인 | 자동화된 배포가 운영 환경까지 진행 |
| 자동화 수준 | 배포 준비 단계까지 자동화 | 전체 프로세스 자동화 |
| 적용 사례 | 운영 환경 배포가 신중히 진행되어야 하는 경우 | 빠른 피드백과 빈번한 릴리스를 원하는 경우 |
CI/CD는 파이프라인으로 구성되며, 각 단계가 자동으로 실행됨
| 도구 | 설명 |
|---|---|
| Jenkins | 가장 인기 있는 오픈소스 CI/CD 도구. 다양한 플러그인으로 확장 가능 |
| GitLab CI/CD | GitLab과 통합된 CI/CD 도구. 코드 관리와 배포를 하나의 플랫폼에서 수행 |
| CircleCI | 클라우드 기반 CI/CD 도구로 간단한 설정과 빠른 빌드를 지원 |
| Travis CI | 오픈소스 프로젝트에 자주 사용되는 CI/CD 도구 |
| AWS CodePipeline | AWS 서비스와 통합된 CI/CD 솔루션 |
| Azure DevOps | Azure 클라우드 환경에서의 CI/CD 솔루션 |
| ArgoCD | Kubernetes 환경에서 GitOps 기반의 지속적 배포 도구 |
| Spinnaker | 멀티클라우드 환경에서 배포 자동화와 관리 기능을 제공 |
| TeamCity | JetBrains에서 제공하는 CI/CD 도구로, 강력한 설정 및 통합 기능을 지원 |
| Bamboo | Atlassian의 CI/CD 도구로, Jira와 연동하여 강력한 워크플로우 관리 지원 |
AWS에서 제공하는 완전 관리형 컨테이너 오케스트레이션 서비스
컨테이너화된 애플리케이션의 배포, 확장, 관리를 간소화하는데 사용됨
Docker 컨테이너를 기반으로, 인프라 없이 컨테이너를 실행하고 오케스트레이션 할 수 있는 기능을 제공
+인프라 프로비저닝: 애플리케이션을 실행하기 위한 서버, 네트워크, 스토리지 등 IT 인프라 자원을 준비하고 설정하는 과정
구조 다이어그램
+---------------------+
| Amazon ECR | <- 컨테이너 이미지 저장
+---------------------+
↓
+---------------------+
| ECS Cluster | <- 컨테이너 실행 환경 (EC2 or Fargate)
+---------------------+
↓
+---------------------+
| ECS Service | <- 작업(Task) 관리 및 트래픽 분산
+---------------------+
↓
+---------------------+
| ECS Task | <- 컨테이너 실행 인스턴스
+---------------------+
↓
+---------------------+
| Docker Container | <- 실제 실행되는 컨테이너
+---------------------+
장점
1. AWS와의 통합: IAM, CloudWatch, VPC 등 AWS 서비스와 긴밀하게 연동
2. 유연한 실행 방식: EC2와 Fargate를 선택적으로 사용 가능
3. 비용 효율성: 서버리스(Fargate)를 통해 필요 리소스만 사용
4. 보안: IAM을 통한 세분화된 권한 관리 및 네트워크 격리
5. 확장성: 트래픽에 따라 컨테이너를 자동 확장
IAM (Identity and Access Management): AWS 리소스의 보안 및 엑세스 관리를 위한 서비스. 사용자와 리스소 간의 권한을 세부적으로 제어하고 리소스 접근 권한을 설정할 수 있음
단점
1. AWS 종속성: AWS 전용 서비스로 멀티 클라우드 환경에서는 제한적
2. Kubernetes와의 비교: EKS(Kubernets 기반)보다는 생태계 확장성이 떨어진다는 평가
| 항목 | Amazon ECS | Amazon EKS |
|---|---|---|
| 초점 | Docker 컨테이너 오케스트레이션 | Kubernetes 기반의 컨테이너 오케스트레이션 |
| 관리 방식 | AWS 전용 오케스트레이션 서비스 | Kubernetes API를 사용하여 멀티 클라우드 지원 가능 |
| 컴퓨팅 옵션 | EC2 및 Fargate 지원 | EC2 및 Fargate 지원 |
| 복잡성 | 간단한 설정과 관리 | Kubernetes의 복잡한 설정 필요 |
| 확장성 | AWS 서비스에 최적화된 확장성 제공 | Kubernetes의 네이티브 확장성 제공 (HPA, VPA 등) |
| 생태계 | AWS 서비스와 긴밀히 통합 (CloudWatch, IAM 등) | Kubernetes 에코시스템(Helm, Kubectl 등)을 활용 가능 |
| 유연성 | AWS 환경에 특화, 멀티 클라우드에는 제한적 | 멀티 클라우드 및 하이브리드 환경에 적합 |
| 러닝 커브 | 상대적으로 쉬운 사용과 관리 | Kubernetes의 러닝 커브가 높음 |
| 비용 | ECS는 기본적으로 무료이며, 리소스 사용량에 따라 비용 발생 | EKS는 관리 비용이 추가됨($0.10/시간/클러스터) |
| 사용 사례 | 단일 클라우드 환경에서 간단한 컨테이너 배포 | 멀티 클라우드, 하이브리드 환경에서 복잡한 워크로드 관리 |
FROM openjdk:17-jdk-slim
VOLUME /tmp
ARG JAR_FILE=build/libs/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

사유 확인

재시도 하고 다시 실패했으나 기다리니 성공


실패함.
후다닥 계정 인증하고 파이프라인을 재생성했다.

초록색 체크가 뜨면 Passed. 누르면 진행 상황을 확인할 수 있다.

아래 파이프라인과 달리 위처럼 모두 passed 상태가 되면 성공한 것이다.
로드 밸런서의 DNS 이름 + 엔드포인트로 정상 배포되었는지 확인

프로젝트에 작성해둔 "/sample" 요청에 정상적으로 응답이 반환함을 확인할 수 있었다.