AM 기반 MSA 기술 열일곱번째 정규수업

오리·2026년 8월 12일

LG AM Inspire camp 5기

목록 보기
32/35

1. AWS와 EC2 이해

AWS는 서버, 네트워크, 저장공간, 데이터베이스 등 다양한 IT 인프라를 인터넷을 통해 제공하는 클라우드 플랫폼이다

직접 물리 서버를 구매하고 구축하지 않아도 필요한 만큼 서버를 생성해서 사용할 수 있다는 점이 특징이다

오늘 실습에서 사용한 EC2는 AWS에서 제공하는 가상 서버 서비스다

전체적인 구조는 다음과 같이 이해할 수 있다

Host PC
   ↓
Internet
   ↓
AWS EC2 Instance
   ↓
Docker
   ↓
Spring Boot Container

EC2 인스턴스를 생성한 뒤 SSH로 접속하면 로컬 Windows가 아닌 AWS에 존재하는 Linux 서버를 직접 제어하게 된다

2. EC2에서 Docker 사용 권한 설정

EC2에 Docker를 설치한 뒤 일반 사용자 계정으로 Docker 명령어를 사용할 수 있도록 다음 명령어를 실행했다

sudo usermod -aG docker ec2-user

-aG docker 옵션은 기존 그룹 정보를 유지하면서 ec2-user를 docker 그룹에 추가한다는 의미다

하지만 이 명령을 실행한 직후 Docker 명령을 사용했을 때 permission denied가 발생할 수 있다

이는 그룹 설정이 현재 로그인된 세션에 즉시 반영되지 않기 때문이다

따라서 SSH 연결을 종료한 뒤 다시 접속하거나 다음 명령을 이용해 새로운 그룹 설정을 적용할 수 있다

newgrp docker

현재 사용자의 그룹은 다음 명령으로 확인할 수 있다

groups

정상적으로 적용되었다면 결과에 docker가 포함되어 있어야 한다

Docker 정상 동작 여부는 다음과 같이 확인할 수 있다

docker ps

3. Docker Hub 이미지 EC2로 가져오기

로컬에서 생성하여 Docker Hub에 업로드해둔 catalog-service 이미지를 EC2로 가져왔다

Docker Hub 계정은 duckfairywak이며, 이미지가 다음과 같이 올라가 있다고 가정하면

duckfairywak/catalog-service:k8s

EC2에서 다음 명령을 실행한다

docker pull duckfairywak/catalog-service:k8s

다운로드된 이미지는 다음 명령으로 확인한다

docker images

이 과정을 통해 개발 PC에 있던 Docker 이미지를 AWS EC2에서도 동일하게 사용할 수 있다는 것을 확인할 수 있다

즉, Docker 이미지는 실행 환경을 하나의 패키지로 만들어 다른 서버에서도 동일한 환경을 재현할 수 있도록 해준다

4. catalog-service 컨테이너 실행

다운로드한 Docker 이미지를 기반으로 컨테이너를 생성한다

예를 들어 Spring Boot 애플리케이션이 컨테이너 내부에서 8088 포트를 사용하고, EC2에서는 8080 포트로 접근하려는 경우 다음과 같이 실행할 수 있다

docker run -d \
  --name catalog-service \
  -p 8080:8088 \
  duckfairywak/catalog-service:k8s

한 줄로 작성하면 다음과 같다

docker run -d --name catalog-service -p 8080:8088 duckfairywak/catalog-service:k8s

여기서

8080:8088
 ↑     ↑
EC2   Container

의 구조로 포트가 연결된다

컨테이너 내부 Spring Boot가 8080으로 동작한다면 다음과 같이 설정해야 한다

docker run -d --name catalog-service -p 8080:8080 duckfairywak/catalog-service:k8s

따라서 Docker 포트 매핑을 할 때는 반드시 애플리케이션이 실제로 사용하는 내부 포트를 확인해야 한다

5. EC2 내부에서 서비스 접근 확인

외부 브라우저에서 접근하기 전에 먼저 EC2 내부에서 서비스가 정상적으로 동작하는지 확인한다

다음과 같이 curl 명령을 사용했다

curl -X GET http://localhost:8080/catalog-service/catalogs

또는 다음처럼 간단히 작성할 수도 있다

curl http://localhost:8080/catalog-service/catalogs

이 요청이 성공하면 적어도 다음 구간은 정상적으로 연결되었다는 의미다

EC2 localhost:8080
        ↓
Docker Port Mapping
        ↓
Container
        ↓
Spring Boot catalog-service

6. Connection reset by peer 오류

curl 요청 과정에서 다음과 같은 오류가 발생했다

Recv failure: Connection reset by peer

이는 해당 포트로 연결 자체를 시도했지만 연결된 서버 또는 컨테이너 쪽에서 연결이 종료된 상태를 의미한다

이 경우 가장 먼저 Docker 컨테이너 상태를 확인해야 한다

docker ps -a

컨테이너가 Exited 상태라면 Spring Boot가 정상적으로 실행되지 않은 것이다

애플리케이션 로그는 다음과 같이 확인할 수 있다

docker logs catalog-service

특히 Spring Boot가 실제로 어떤 포트에서 실행되는지 확인하는 것이 중요하다

예를 들어 로그에서

Tomcat started on port 8080

이라고 나온다면 Docker 실행 시 컨테이너 포트도 8080을 지정해야 한다

docker run -d --name catalog-service -p 8080:8080 ...

반대로 Spring Boot가 8088에서 실행된다면

docker run -d --name catalog-service -p 8080:8088 ...

처럼 연결해야 한다

따라서 이번 오류를 통해 Docker의 Host Port와 Container Port를 단순히 임의로 설정하는 것이 아니라 실제 애플리케이션 포트와 정확히 일치시켜야 한다는 점을 확인했다

7. AWS Public DNS와 보안 그룹

EC2 내부에서 서비스 접근이 성공했다면 다음 단계는 Host PC에서 EC2에 접근하는 것이다

AWS EC2에는 인터넷에서 접근할 수 있는 Public IPv4 DNS 또는 Public IP가 존재한다

예를 들면 다음과 같은 형태다

ec2-xx-xx-xx-xx.ap-northeast-2.compute.amazonaws.com

외부 브라우저에서는 다음과 같이 접근할 수 있다

http://<EC2-Public-DNS>:8080/catalog-service/catalogs

하지만 EC2에서 Docker의 8080 포트를 열었다고 해서 바로 인터넷에서 접근할 수 있는 것은 아니다

AWS에는 Security Group이라는 네트워크 방화벽 설정이 존재한다

따라서 EC2의 인바운드 규칙에서 8080 포트를 허용해야 한다

Type   : Custom TCP
Port   : 8080
Source : My IP

실습 상황에서는 모든 IP에 개방할 수도 있지만, 실제 환경에서는 필요한 IP에만 제한하는 것이 안전하다

전체 접근 흐름은 다음과 같다

Host PC Browser
      ↓
Internet
      ↓
AWS Security Group
      ↓
EC2 Public DNS : 8080
      ↓
Docker Port Mapping
      ↓
catalog-service Container
      ↓
Spring Boot

8. Kubernetes NodePort 복습

AWS 실습을 진행하기 전에 Kubernetes에서 사용했던 NodePort도 다시 정리했다

Kubernetes에서는 Spring Boot 애플리케이션을 일반적으로 Pod 내부에서 실행한다

Deployment
   ↓
Pod
   ↓
Container
   ↓
Spring Boot

Pod는 Kubernetes 내부 IP를 사용하기 때문에 외부의 브라우저나 Postman이 Pod에 직접 접근하기 어렵다

이를 위해 Kubernetes에서는 Service를 사용한다

외부 사용자
    ↓
Service
    ↓
Pod

그중 NodePort는 Kubernetes Node의 특정 포트를 외부에 공개하는 방식이다

예를 들어 user-service를 다음과 같이 구성할 수 있다

ports:
  - port: 8081
    targetPort: 8081
    nodePort: 32081

각 포트는 다음 의미를 가진다

nodePort   32081
  ↓
Kubernetes Node의 외부 공개 포트

port       8081
  ↓
Service가 사용하는 포트

targetPort 8081
  ↓
실제 Pod 내부 애플리케이션 포트

외부 요청의 흐름은 다음과 같다

Postman
   ↓
Node IP : 32081
   ↓
NodePort
   ↓
Service
   ↓
targetPort 8081
   ↓
Pod
   ↓
Spring Boot user-service

따라서 NodePort를 이용하면 다음과 같은 방식으로 접근할 수 있다

http://<Node-IP>:32081/users

NodePort와 AWS EC2의 포트 공개 방식은 외부에서 특정 포트로 서버에 접근한다는 점에서는 비슷하게 느껴질 수 있지만, 역할은 다르다

NodePort는 Kubernetes 내부 Service 기능이고, AWS Security Group은 EC2 수준에서 외부 네트워크 접근을 허용하거나 차단하는 방화벽 역할을 한다

9. 오늘의 핵심 흐름

오늘 실습은 결국 다음 흐름으로 정리할 수 있다

Docker Image 생성
      ↓
Docker Hub Push
      ↓
AWS EC2 생성
      ↓
EC2 Docker 설치
      ↓
docker pull
      ↓
Container 실행
      ↓
EC2 내부 curl 테스트
      ↓
Security Group 8080 허용
      ↓
Public DNS 확인
      ↓
Host PC에서 접근

기존에는 내 PC에서 Docker 컨테이너를 실행했다면, 오늘은 AWS EC2라는 원격 서버에서 동일한 Docker 이미지를 실행했다는 차이가 있다

Docker를 이용하면 애플리케이션과 실행 환경을 이미지로 만들어두고 로컬 PC, 다른 서버, 클라우드 환경에서도 동일하게 실행할 수 있다

또한 서비스를 외부에 공개할 때는 애플리케이션의 포트만 고려하는 것이 아니라 Docker 포트 매핑, Kubernetes Service, AWS Security Group 등 각 계층의 네트워크 설정이 모두 맞아야 한다는 점이 중요했다

profile
IT 전공자의 발버둥

0개의 댓글