이번엔 네트워크 7계층의 애플릐케이션 계층에서 외부 트래픽을 처리하는 ingress 리소스에 살펴보겠습니다.
많은 웹 서비스는 애플리케이션 계층에서 네트워크 통신을 수행하는데 주로 HTTP. HTTPS를 사용하여 서비스를 제공합니다.
쿠버네티스에선 클러스터로 들어오는 트래픽을 관장할 수 있는 메커니즘을 제공합니다.
Ingress란?
Ingress는 네트워크 7계층에 대한 설정을 담당하는 리소스로 가장 외부 HTTP 호출에 대한 트래픽을 처리하는 역할을 합니다.
부하 분산, TLS 종료, 도메인 기반 라우팅 기능 등을 제공합니다.
이는 쿠버네티스 클러스터 내부 서비스에 외부 접근 가능한 URL을 부여해 일반 사용자들이 쉽게 접근할 수 있는 통로를 제공합니다.
그에 맞는 Ingress Controller가 존재합니다. 이는 Ingress에 정의된 트래픽 라우팅 규칙을 보고 라우팅을 수행합니다.

Ingress Controller란?
Ingress는 리소스 자체로 어떤 프로그램이 작동하는 코드가 아닌 트래픽 처리에 대한 정보를 담는 정의에 가깝습니다.
실제 Ingress 규칠을 읽고 외부의 트래픽을 Service로 전달하는 주체는 Ingress Controller입니다.
쿠버네티스 리소스는 해당 리소스에 대응하는 리소스 컨트롤러가 존재합니다. Ingress 리소스도 마찬가지구요.
하지만 Ingress Controller는 쿠버네티스 내장 컨트롤러와 다르게 사용자의 목적과 용도에 맞게 명시적으로 컨트롤러를 설치해야 합니다.
Ingress Controller의 종류엔 다음과 같이 있습니다.
- NGINX Ingress
- HAProxy
- AWS ALB Ingress Controller
- Ambassador
- Kong
- treafik
이 밖에도 더 많은 종류들이 있습니다.
NGINX Ingress Controller 설치
NGINX Ingress Controller는 가장 많이 사용되는 제품 중 하나입니다.
helm을 이용해 손쉽게 NGINX Ingress Controller를 설치할 수 있습니다.
# NGINX Ingress Controller를 위한 네임스페이스를 생성합니다.
kubectl create ns ctrl
# namespace/ctrl created
# nginx-ingress 설치
helm install ingress stable/nginx-ingress --version 1.40.3 -n ctrl
# NAME: ingress
# LAST DEPLOYED: Wed Mar 11 13:31:14 2020
# NAMESPACE: ctrl
# STATUS: deployed
# REVISION: 1
# TEST SUITE: None
# NOTES:
# ...
NGINX Ingress Controller 관련 Pod와 Service가 생성된 것을 확일할 수 있습니다.

로드벨런서 타입의 Service에 80포트와 443포트가 열린 것을 확인할 수 있습니다.
앞으로 Ingress로 들어오는 모든 트래픽은 ingress-controller-service로 들어오게 됩니다.
Ingress 기본 사용법
도메인 주소 테스트
Ingress는 Layer 7 통신이기 때문에 도메인 주소를 가지고 있어야 제대로 된 Ingress테스트를 할 수 있습니다.
https://sslip.io를를 통해 도메인 주소를 얻을 수 있씁니다.
https://sslip.io의 서브 도메인에 IP를 입력하면 해당하는 IP를 DNS lookup 결과로 반환합니다.
이 서비스를 통해 Ingress 실습을 진행하겠습니다.
다음 명령을 통해 Ingress Controller IP를 확인할 수 있습니다. 호스트 서버(마스터, 워커) 중 하나의 내부IP가 반환될 것입니다.
INGRESS_IP=$(kubectl get svc -nctrl ingress-nginx-ingress-controller -ojsonpath="{.status.loadBalancer.ingress[0].ip}")
echo $INGRESS_IP
# 10.0.1.1
Ingress 생성
Ingress와 연결할 nginx 서비스부터 생성합니다.
kubectl run mynginx --image nginx --expose --port 80
# pod/mynginx created
# pod/service created
# comma로 여러 리소스를 한번에 조회할 수 있습니다.
kubectl get pod,svc mynginx
# NAME READY STATUS RESTARTS AGE
# pod/mynginx 1/1 Running 0 8m38s
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# service/mynginx ClusterIP 10.43.203.151 <none> 80/TCP 8m38s
Ingress 리소스를 정의합니다.
# mynginx-ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
name: mynginx
spec:
rules:
- host: 10.0.1.1.sslip.io
http:
paths:
- path: /
backend:
serviceName: mynginx
servicePort: 80
- annotations: 메타정보를 저장하기 위한 property로 label과 비슷하지만 annotations으로는 필터링 하지 못하고 단지 메타데이터를 저장하는 용도로 사용합니다. Ingress에선 Ingress Controller에게 메타정보를 전달할 목적으로 사용됩니다.
예로 kubernetes.io/ingress.class: nginx의 의미는 해당 Ingress가 NGINX Ingress Controller에 의해 처리될 것을 명시한 것입니다. - rules: 외부 트래픽을 어떻게 처리할지 정의합니다.
- rules[0].host: 특정 도메인으로 들어오는 트래픽에 대해 라우팅을 정의합니다. 생략 시 모든 호스트 트래픽(*)을 처리합니다.
- rules[0].http.paths[0].path: Ingress path를 정의합니다.
- rules[0].http.paths[0].backend: Ingress의 트래픽을 받을 Service와 포트를 정의합니다.
kubectl apply -f mynginx-ingress.yaml
# ingress.extensions/mynginx created
kubectl get ingress
# NAME CLASS HOSTS ADDRESS PORTS AGE
# mynginx <none> 10.0.1.1.sslip.io 10.0.1.1 80 10m
# mynginx 서비스로 연결
curl 10.0.1.1.sslip.io
# <!DOCTYPE html>
# <html>
# <head>
# <title>Welcome to nginx!</title>
# ...
위처럼 Ingress를 생성합니다.
해당 Ingress는 10.0.1.1.sslip.io:80/ 트래픽을 mynginx 서비스의 80포트로 전달합니다.
도메인 기반 라우팅
이번엔 서브 도메인 주소를 이용해 도메인 기반 라우팅 규칙을 정의해보겠습니다.
서브 도메인별 연결된 서비스를 2개 생성합니다.
# apache web server
kubectl run apache --image httpd --expose --port 80
# pod/apache created
# service/apache created
# nginx web server
kubectl run nginx --image nginx --expose --port 80
# pod/nginx created
# service/nginx created
# domain-based-ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
name: apache-domain
spec:
rules:
# apache 서브 도메인
- host: apache.10.0.1.1.sslip.io
http:
paths:
- backend:
serviceName: apache
servicePort: 80
path: /
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
name: nginx-domain
spec:
rules:
# nginx 서브 도메인
- host: nginx.10.0.1.1.sslip.io
http:
paths:
- backend:
serviceName: nginx
servicePort: 80
path: /
각 서브 도메인이 다음과 같이 라우팅 됩니다.
- apache.10.0.0.1.sslip.io -> apache:80/
- nginx.10.0.0.1.sslip.io -> nginx:80/
kubectl apply -f domain-based-ingress.yaml
# ingress.extensions/apache-domain created
# ingress.extensions/nginx-domain created
curl apache.10.0.1.1.sslip.io
# <html><body><h1>It works!</h1></body></html>
curl nginx.10.0.1.1.sslip.io
# <!DOCTYPE html>
# <html>
# <head>
# <title>Welcome to nginx!</title>
# ...
IP 주소는 동일해도 도메인 주소를 기준으로 서로 다른 서비스로 트래픽을 라우팅 할 수 있지요.
Path 기반 라우팅
URL path기반 라우팅도 가능합니다.
이미 생성한 nginx, apache Servere에 대해서 path 기반 Ingress를 구성합니다.
# path-based-ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /
name: apache-path
spec:
rules:
- host: 10.0.1.1.sslip.io
http:
paths:
- backend:
serviceName: apache
servicePort: 80
path: /apache
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /
name: nginx-path
spec:
rules:
- host: 10.0.1.1.sslip.io
http:
paths:
- backend:
serviceName: nginx
servicePort: 80
path: /nginx
annotation에 다음과 같은 설정값이 추가됩니다.
nginx의 rewrite 지시자와 동일하게 프록시되는 서버에 path를 /로 재정의합니다. 그렇지 않으면 Ingress로 들어오는 URL path가 그대로 서비스에 전달돼 정상동작이 안됩니다.
예로 nginx 서버로 /nginx path가 요청되어 결과적으로 404에러가 발생합니다.
- nginx.ingress.kubernetes.io/rewrite-target: path 재정의 지시자
kubectl apply -f path-based-ingress.yaml
# ingress.extensions/apache-path created
# ingress.extensions/nginx-path created
curl 10.0.1.1.sslip.io/apache
# <html><body><h1>It works!</h1></body></html>
curl 10.0.1.1.sslip.io/nginx
# <!DOCTYPE html>
# <html>
# <head>
# <title>Welcome to nginx!</title>
# ...
URI path로 각 서버로 접근하면 응답되는 것을 확인할 수 있습니다.
Ingress리소스를 통해 외부 트래픽을 처리해야 할 때, 매번 로드밸런서를 생성하지 않고도 애플리케이션 레이어에서 path 및 도메인 기반 트래픽 라우팅이 가능합니다.
Basic Auth 설정
Ingress리소스에 간단 HTTP Authentication 기능을 추가할 수 있습니다.
Nginx Ingress Controller도 결국 NGINX 서버를 기반으로 동작해 NGINX 서버에서 제공한느 대부분의 기능들을 동일하게 사용 가능합니다.
HTTP Authentication 종류 중 하나인 Basic Auth를 이용해 외부 사용자 접근에 대한 최소한의 보안 절차를 설정해봅시다.
Basic Authentication
HTTP 프로토콜에는 자체적으로 인증을 위한 메커니즘이 설계되어 있습니다.
그 중에 Basic Authentication은 간단한 유저ID, 비밀번호를 HTTP 헤더로 전달하여 인증합니다.
아래와 같이 콜론으로 묶어 base64로 인코딩 하여 전달합니다.
Authorization: Basic $BASE64(user:password)
예로 한 사이트는 user를 foo, 비밀번호를 bar로 Basic Auth 인증을 하는 페이지라면 다음과 같이 접속 가능합니다.
# 헤더 없이 접속 시도
curl -v https://httpbin.org/basic-auth/foo/bar
# HTTP/2 401
# ...
# www-authenticate: Basic realm="Fake Realm"
# basic auth 헤더 전송
curl -v -H "Authorization: Basic $(echo -n foo:bar | base64)" https://httpbin.org/basic-auth/foo/bar
# HTTP/2 200
# ..
# {
# "authenticated": true,
# "user": "foo"
# }
헤더가 없이 전송하면 401 Unathorized 코드를 응답받고 적절한 인증 정보를 헤더에 첨부하여 전달하면 정상 200 코드를 반환받습니다.
이는 curl 명령 뿐만 아니라 웹브라우저를 통해 인증이 가능합니다.
Basic Auth 설정
사용자 정보를 담고 있는 basic authentication파일을 생성합니다.
이를 위해 htpasswd라는 툴을 설치합니다.
# htpasswd binary 설치
sudo apt install -y apache2-utils
# 아이디는 foo, 비밀번호는 bar인 auth 파일 생성
htpasswd -cb auth foo bar
# 생성한 auth 파일을 Secret으로 생성합니다.
kubectl create secret generic basic-auth --from-file=auth
# Secret 리소스 생성 확인
kubectl get secret basic-auth -oyaml
# apiVersion: v1
# data:
# auth: Zm9vOiRhcHIxJE1UTy9MMUN0JEdNek8xOVZtMXdKYWt6R0tjLjhQTS8K
# kind: Secret
# metadata:
# name: basic-auth
# namespace: default
# resourceVersion: "3648288"
# selfLink: /api/v1/namespaces/default/secrets/basic-auth
# uid: b9966176-5259-4e3f-8476-c7e308ae21a1
# type: Opaque
이 basic-auth Secret 리소스를 Ingress에 설정해야합니다.
Basic Auth도 annotation을 이용해 설정할 수 있습니다.
# apache-auth.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/auth-type: basic
nginx.ingress.kubernetes.io/auth-secret: basic-auth
nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required - foo'
name: apache-auth
spec:
rules:
- host: apache-auth.10.0.1.1.sslip.io
http:
paths:
- backend:
serviceName: apache
servicePort: 80
path: /
- nginx.ingress.kubernetes.io/auth-type: basic auth 인증 방식을 설정합니다.
- nginx.ingress.kubernetes.io/auth-secret: 사용자 auth 파일이 저장된 secret이름을 지정합니다.
- nginx.ingress.kubernetes.io/auth-realm: relm을 설정합니다. (보안 인증 영역)
이와 같이 설정하면 단순 HTTP 요청만으론 접근이 불가하고 적절한 사용자 정보 HTTP헤더로 추가해줘야 정상 응답을 받을 수 있습니다.
curl -I apache-auth.10.0.1.1.sslip.io
# HTTP/1.1 401 Unauthorized
# Server: nginx/1.17.10
# Date: Tue, 07 Jul 2020 12:30:43 GMT
# Content-Type: text/html
# Content-Length: 180
# Connection: keep-alive
# WWW-Authenticate: Basic realm="Authentication Required - foo"
curl -I -H "Authorization: Basic $(echo -n foo:bar | base64)" apache-auth.10.0.1.1.sslip.io
# HTTP/1.1 200 OK
# Server: nginx/1.17.10
# Date: Tue, 07 Jul 2020 12:31:14 GMT
# Content-Type: text/html
# Content-Length: 45
# Connection: keep-alive
# Last-Modified: Mon, 11 Jun 2007 18:53:14 GMT
# ETag: "2d-432a5e4a73a80"
# Accept-Ranges: bytes
TLS 설정
대부분의 웹 브라우저는 TLS가 적용된 HTTPS 서비스를 요구합니다.
Ingress 리소스는 TLS를 손쉽게 적용할 수 있는 방법을 제공합니다.
annotations에 Self-signed 인증서나 정식 CA를 통해 서명된 인증서에 대한 정보를 등록하면 바로 HTTPS 서비스를 제공할 수 있습니다.
Self-signed 인증서 설정
Self-signed 인증서는 CA로 부터 정식 인증서를 발급받지 않은 직접 서명한 인증서입니다.
공인 발급기관으로 인증받은 인증서가 아니라 경고가 뜨지만 간편히 테스트 용으로 유용합니다.
Self-signed 인증서 생성
다음과 같이 openssl을 이용해 self-signed 인증서를 생성합니다.
-sunj "/CN="의 도메인 주소는 알맞게 수정하면 됩니다.
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=apache-tls.10.0.1.1.sslip.io"
# Generating a RSA private key
# ...................................................+++++
# .....+++++
# writing new private key to 'tls.key'
# -----
tls.crt # 인증서
tls.key # 개인키
self-signed인증서를 Secret 리소스 형태로 저장합니다.
cat << EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
name: my-tls-certs
namespace: default
data:
tls.crt: $(cat tls.crt | base64 | tr -d '\n')
tls.key: $(cat tls.key | base64 | tr -d '\n')
type: kubernetes.io/tls
EOF
- type: 기본 Opaque이 아닌 인증서를 보관할 kubernetes.io/tls 타입을 사용
Ingress TLS 설정하기
마지막으로 TLS가 적용된 HTTPS Ingress를 생성합니다.
# apache-tls.yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: apache-tls
spec:
tls:
- hosts:
- apache-tls.10.0.1.1.sslip.io
secretName: my-tls-certs
rules:
- host: apache-tls.10.0.1.1.sslip.io
http:
paths:
- path: /
backend:
serviceName: apache
servicePort: 80
- tls[0].hosts: tls를 적용할 도메인을 입력. 앞에서 생성한 인증서의 CN 정보를 넣습니다.
- tls[0].secretName: 인증서와 개인키가 저장된 Secret 리소스의 이름을 입력합니다.
kubectl apply -f apache-tls.yaml
# ingress.networking.k8s.io/apache-tls created
위와 같이 진행 후 TLS가 적용된 도메인을 사용할 수 있습니다.
유효하지 않은 인증서라 경고가 뜨지만 기본 tls 기능을 만족합니다.
cert-manager를 이용한 인증서 발급 자동화
자체 서명 인증서를 직접 생성하고 HTTPS 서버를 구축했는데
이를 자동화하고 정식 CA를 통해 인증서를 발급받을 수 있는 방법이 있습니다.
cert-manager는 쿠버네티스 X509 인증서 관리 컴포넌트 입니다.
공인 인증서 발급과 갱신을 도와줍니다.
cert-manager 설치
helm을 이용해 설치합니다.
새로운 helm repo를 추가하고 해당 repo에서 cert-manager를 설치합니다.
# cert-manager라는 네임스페이스 생성
kubectl create namespace cert-manager
# cert-manager 관련 사용자 정의 리소스 생성
kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v0.15.1/cert-manager.crds.yaml
# customresourcedefinition.apiextensions.k8s.io/issuers.cert-manager.io created
# customresourcedefinition.apiextensions.k8s.io/orders.acme.cert-manage...
# ...
# jetstack 레포지토리 추가
helm repo add jetstack https://charts.jetstack.io
#"jetstack" has been added to your repositories
# 레포지토리 index 업데이트
helm repo update
# Hang tight while we grab the latest from your chart repositories...
# ...Successfully got an update from the "jetstack" chart repository
# cert-manager 설치
helm install \
cert-manager jetstack/cert-manager \
--namespace cert-manager \
--version v0.15.1
Issuer 생성
이제 인증서 발급을 도와줄 Issure 리소스를 생성해봅시다.
이는 내장 리소스가 아니라 cert-manager에서 생성한 사용자 정의 리소스입니다.
Ingress의 설정값을 참조하여 Let's encrypt라는 사이트를 통해 인증서를 발급받습니다.
Issuer는 크게 ClusterIssuer와 Issuer 종류가 있습니다.
네임스페이스와 상관없이 클러스터 레벨에서 동작하는 발급자를 ClusterIssuer
특정 네임스페이스 안의 Ingress만 관리하는 발급자를 Issuer라 합니다.
이번엔 ClusterIssuer를 생성합니다.
# http-issuer.yaml
apiVersion: cert-manager.io/v1alpha2
kind: ClusterIssuer
metadata:
name: http-issuer
spec:
acme:
email: <EMAIL>
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: issuer-key
solvers:
- http01:
ingress:
class: nginx
- apiVersion: cert-manager에서 정의한 apiVersion을 명시
- Kind: cluster레벨 발급자 지정
- acme: 자동 인증서 생성 및 연장을 관리해 주는 타입. CA, Vault 등 다른 타입도 존재
- email: 사용자 이메일 입력 ( 만료 예정일 및 이슈 등 발송)
- server: 어떤 acme 서버를 사용할지 지정
- privateKeySecretRef: 사용자의 개인키를 저장할 Secret 리소스 이름 지정
- solvers: 도메인 주소에 대한 소유권 증명 방법 선택. 크게 http(http01)요청과 DNS 방법이 있음
- ingress: 그때 사용하는 Ingress 컨트롤러로 NGINX 사용
ClusterIssuer 리소스를 생성합니다.
kubectl apply -f http-issuer.yaml
# clusterissuer.cert-manager.io/http-issuer created
kubectl get clusterissuer
# NAME READY AGE
# http-issuer True 2m
cert-manager가 관리하는 Ingress 생성
이제 cert-manager를 이용해 TLS가 적용된 Ingress를 생성해보겠습니다.
# apache-tls-issuer.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
# 앞서 생성한 발급자 지정
cert-manager.io/cluster-issuer: http-issuer
name: apache-tls-issuer
spec:
rules:
# 10.0.1.1을 공인IP로 변경해 주세요.
- host: apache-issuer.10.0.1.1.sslip.io
http:
paths:
- backend:
serviceName: apache
servicePort: 80
path: /
tls:
- hosts:
# 10.0.1.1을 공인IP로 변경해 주세요.
- apache-issuer.10.0.1.1.sslip.io
secretName: apache-tls
- cert-manager.io/cluster-issuer: cert-manager에서 제공하는 발급자 이름을 지정
- tls[0].hosts: TLS를 적용할 도메인 이름을 입력합니다.
- tls[0]. secretName: self-signed 인증서와는 다르게 사용자가 직접 인증서와 개인키가 포함된 Secret 리소스를 생성하지 않아도 cert-manager에서 자동으로 인증서를 발급받아 Secret을 생성합니다. 사용자는 생성될 Secret의 이름만 지정합니다.
kubectl apply -f apache-tls-issuer
# ingress.networking.k8s.io/apache-tls-issuer created
kubectl get certificate
# NAME READY SECRET AGE
# apache-tls False apache-tls 38s
kubectl get certificate
# NAME READY SECRET AGE
# apache-tls True apache-tls 75s
위 명령을 통해 잠시 기다리면 정상 적용이 됩니다.
브라우저를 통해 확인이 가능합니다.
마무리
이번엔 Layer7 레벨의 트래픽을 관리하는 Ingress 리소스를 살펴보았습니다.
예시로 사용한 NGINX Ingress Controller와 다른걸 사용하면 설정이 다를 수 있으나 큰 그림은 같습니다.
많은 서비스가 HTTP 통신을 사용하여 Ingress가 자주 사용됩니다.
'개발 > DevOps' 카테고리의 다른 글
| [Kubenetes] 접근제어 - HTTP Basic Authentication, X.509 인증서, RBAC (1) | 2025.12.23 |
|---|---|
| [Kubenetes] 스토리지 - PersistentVolume, PersistentVolumeClaim, StorageClass (1) | 2025.11.11 |
| [kubernetes] helm 패키지 매니저 (0) | 2025.10.06 |
| [Kubernetes] 쿠버네티스 컨트롤러 2 - StatefulSet, Job & CronJob (0) | 2025.10.04 |