심심한 개발자의 취미생활

app, docker, kubernetes 인프라 환경의 포트 설정

  • Docker와 쿠버네티스를 학습하면서 통신 포트를 설정하는 부분에서 많은 혼돈이 왔다. 코드로 포트를 설정했는데 Docker image에도 포트 작성이 있고, 쿠버네티스에서도 Deployment, Service 에도 작성하는 곳이 있다. 그래서 각 부분의 포트 설정이 어떤 역할을 하고 어떻게 작성해댜 되는지 정리를 하였다.

핵심 포트 설정의 4가지의 역할

Application의 구동 포트 설정

  • 역할

    • Application의 코드상에서 설정된 포트는 실제 구동 환경 (local, cloud, 가상 환경 등)에서 프로세스가 동작하는 포트를 설정한다.
  • 동작

    • 코드 상의 포트 설정은 실제 구동 포트로 최종적으로 요청 메시지가 도달해야 되는 포트를 지정하는 역할을 한다.
// node server
const express = require('express')
const app = express()

const port = 3000

app.listen(port, () => {
    console.log(`start server : ${port}`)
})

app.get('/', (req, res) => {
    res.send('node express server')
})

Dockerfile의 `EXPOSE`

  • 역할
    • EXPOSE는 이 컨테이너 이미지가 어떤 포트를 사용할 것인지에 대한 정보와 문서를 제공하는 역할만을 가진다.
  • 동작
    • EXPOSE 키워드는 실제로 포트를 외부에 개방하지 않는다.
    • docker run -p 옵션이나 쿠버네티스의 설저잉 없다면 아무런 기능도 하지 않는다.
    • 쿠버네티스는 Dockerfile의 EXPOSE 설정을 완전히 무시하여, 이 값이 있든 없든 쿠버네티스의 네트워크 동작에는 아무런 영향을 주지 않는다.
    • 이미지 속 사용 포트에 대하여 사용자에게 정보를 제공하는 역할로 작성은 좋은 개발 습관이라 할 수 있다. 하지만 기능적으로는 필수가 아니다.
# Dockerfile
FROM node:22-slim
...
EXPOSE 3000
...

kubernetes Deployment의 containerPort

  • 경로 - .spec.template.spec.containers.ports.containerPort
  • 역할
    • 이 설정 또한 EXPOSE와 유사하게, 해당 컨테이너가 어떤 포트에서 요청을 기다리고 있는지에 대한 명시하는 정보 제공 및 문서화의 역할이 강하다.
  • 동작
    • 이 값을 설정하지 않아도, 컨테이너 내부의 애플리케이션이 특정 포트에서 실행 중이라면 Service는 해당 Pod로 트래픽을 전달할 수 있으며, 네트워크 연결을 위해 필수가 아니다.
    • 다만 클러스터 관리자가 Pod의 명세를 보고 어떤 포트가 사용되는지 쉽게 파악할 수 있으며, 포트에 name을 지정할 수 있게 해줘, Service 선언에서 targetPort를 숫자가 아닌 이름으로 참조할 수 있게 해주어 유연하고 안정적인 설정을 가능하게 지원한다.
apiVersion: apps/v1
kind: Deployment

...

spec:
  template:
    spec:
      containers:
        - name: [container-name]
          ports:
            - name: node
              containerPort: 3000

...

kubernetes Service의 port와 targetPort

  • 경로 - .spec.ports.port / .spec.ports.targetPort

  • 역할

    • 이 섹션은 실제로 쿠버네티스 클러스터의 네트워크 라우팅을 구성하는 핵심적인 역할을 한다.
    • 쿠버네티스 네트워킹의 실질적인 동작을 정의한다.
  • 동작

    • .spec.ports.port : Service 자체가 노출하는 포트로 클러스터 내의 다른 Pod들 은 이 port를 통해 해당 서비스에 접근한다.
    • .spec.ports.targetPort : Service가 트래픽을 최종적으로 전달할 대상 파드(Pod)의 컨테이너 포트이다. 컨테이너 내부에서 애플리케이션이 실제로 실행중인 포트 번호이다.
    • 외부 요청 -> Service의 IP:port -> Pod의 IP:targetPort
apiVersion: v1
kind: Service

...
spec:
  ports:
    # port로 들어온 트래픽을 파드의 targetPort로 트래픽을 전달한다.
    # targetPort가 생략되어 있다면 port와 동일한 포트로 트래픽을 전달한다.
    - port: 8000
      targetPort: 3000