istio 스터디 2주차 내용을 정리하였다.

Istio 프록시의 실제 동작 도구인 Envoy 프록시에 대한 내용과 secure istio에 대한 내용을 다루었다.

그럼시작한다.

Envoy란 ?

Envoy는 원래 Lyft에서 개발된 고성능 오픈소스 프록시(proxy)입니다. 주로 마이크로서비스 아키텍처에서 서비스 간 트래픽을 중계하고, 로드밸런싱, 서비스 디스커버리, TLS 암호화, 서킷 브레이커, 트래픽 라우팅, 모니터링 등 다양한 네트워크 기능을 제공한다. Envoy의 가장 큰 특징은 API 기반의 실시간 설정 업데이트와 뛰어난 가시성과 성능이다.

istio가 Envoy 프록시를 사이드카로 활용하여 서비스 메시를 구현하고, 트래픽 관리·보안·모니터링 등 다양한 기능을 제공하는 오픈소스 플랫폼이기 때문에 Envoy 프록시를 필히 알아야 한다.

Envoy의 가장 큰 장점은 동적 구성(Dynamic Configuration)과 API 기반 관리이다.
이 장점 덕분에 실시간으로 프록시 설정(트래픽 라우팅, 보안 정책, 로드밸런싱 등)을 변경할 수 있고, 서비스 중단 없이 네트워크 정책을 빠르게 반영할 수 있다.

예를 들어, 대규모 마이크로서비스 환경에서 특정 서비스에 장애가 발생했을 때, 운영자는 Envoy의 xDS API를 통해 실시간으로 트래픽을 우회하거나 라우팅 정책을 수정할 수 있다. 이 과정에서 애플리케이션이나 프록시를 재시작할 필요가 없으므로, 서비스 연속성과 가용성을 향상 시킬 수 있다. DevOps 엔지니어 입장에서는 배포 자동화 파이프라인이나 운영 도구와 연동해 네트워크 정책을 코드로 관리하고, 장애 대응이나 신규 서비스 추가 시에도 빠르고 유연하게 대응할 수 있다.

Envoy 실습

docker pull envoyproxy/envoy:v1.19.0
docker pull curlimages/curl
docker pull mccutchen/go-httpbin

# mccutchen/go-httpbin 는 기본 8080 포트여서, 책 실습에 맞게 8000으로 변경
# docker run -d -e PORT=8000 --name httpbin mccutchen/go-httpbin -p 8000:8000
docker run -d -e PORT=8000 --name httpbin mccutchen/go-httpbin 
docker ps

# curl 컨테이너로 httpbin 호출 확인
docker run -it --rm --link httpbin curlimages/curl curl -X GET http://httpbin:8000/headers

여기까지는 envoy를 타지않고 httpbin 컨테이너로 바로 접속한 모습이다.

admin:  # Envoy 관리 인터페이스 설정
  address:  # 관리 인터페이스 주소 구성
    socket_address: { address: 0.0.0.0, port_value: 15000 }  # 모든 IP에서 15000 포트로 관리 인터페이스 개방

static_resources:  # 정적 리소스 정의(리스너, 클러스터 등)
  listeners:  # 트래픽 수신을 위한 리스너 목록
  - name: httpbin-demo  # 리스너 식별 이름
    address:  # 리스너 바인딩 주소
      socket_address: { address: 0.0.0.0, port_value: 15001 }  # 모든 IP에서 15001 포트로 트래픽 수신
    filter_chains:  # 필터 체인 구성
    - filters:  # 네트워크 필터 목록
      - name:  envoy.filters.network.http_connection_manager  # HTTP 연결 관리 필터 사용
        typed_config:  # 타입 지정 구성
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager  # gRPC API 타입 지정
          stat_prefix: ingress_http  # 메트릭 접두사 설정
          http_filters:  # HTTP 필터 스택
          - name: envoy.filters.http.router  # 라우터 필터 사용(기본 요청 라우팅)
          route_config:  # 라우팅 구성
            name: httpbin_local_route  # 라우트 구성 이름
            virtual_hosts:  # 가상 호스트 목록
            - name: httpbin_local_service  # 가상 호스트 이름
              domains: ["*"]  # 모든 도메인 매칭
              routes:  # 라우팅 규칙 목록
              - match: { prefix: "/" }  # 모든 경로(/로 시작) 매칭
                route:  # 라우팅 대상 설정
                  auto_host_rewrite: true  # 업스트림 호스트 헤더 자동 재작성
                  cluster: httpbin_service  # 타겟 클러스터 지정
  clusters:  # 업스트림 서비스 클러스터 정의
    - name: httpbin_service  # 클러스터 이름
      connect_timeout: 5s  # 연결 타임아웃 설정(5초)
      type: LOGICAL_DNS  # DNS 기반 서비스 디스커버리 사용
      dns_lookup_family: V4_ONLY  # IPv4 전용 DNS 조회
      lb_policy: ROUND_ROBIN  # 라운드 로빈 로드 밸런싱 정책
      load_assignment:  # 엔드포인트 할당 정보
        cluster_name: httpbin  # 대상 클러스터 이름(실제 서비스 이름)
        endpoints:  # 엔드포인트 그룹
        - lb_endpoints:  # 로드밸런싱 대상 엔드포인트
          - endpoint:  # 단일 엔드포인트 설정
              address:  # 대상 주소
                socket_address:  # 소켓 주소 지정
                  address: httpbin  # 서비스 도메인 주소(httpbin)
                  port_value: 8000  # 대상 포트(8000)

위의 설정파일을 사용하여 엔보이를 실행시킨다.

그리고 다음 명령어로 envoy

docker run --name proxy --link httpbin envoyproxy/envoy:v1.19.0 --config-yaml "$(cat ch3/simple.yaml)"

그다음 다시 다음 명령어로 엔보이 컨테이너로 붙어본다.

docker run -it --rm --link proxy curlimages/curl curl -X GET http://proxy:15001/headers

그럼 다음 화면처럼 아까완 다른 헤더값

  • X-Envoy-Expected-Rq-Timeout-Ms
  • X-Request-Id

들이 추가되면서 결국 httpbin 의 결과가 출력되는것을 알 수 있다. 이는 곧 엔보이 프록시를 통해 httpbin 컨테이너에 접속된것을 알 수 있다.

이것들은 envoy의 설정을 바꾸면 해당값도 바뀐다.

              - match: { prefix: "/" }
                route:
                  auto_host_rewrite: true
                  cluster: httpbin_service
                  timeout: 1s

보는것처럼 타임아웃 값이 1.5초에서 1초로 바뀐것을 알 수 있다.

# 추가 테스트 : Envoy Admin API(TCP 15000) 를 통해 delay 설정
docker run -it --rm --link proxy curlimages/curl curl -X POST http://proxy:15000/logging
docker run -it --rm --link proxy curlimages/curl curl -X POST http://proxy:15000/logging?http=debug

docker run -it --rm --link proxy curlimages/curl curl -X GET http://proxy:15001/delay/0.5
docker run -it --rm --link proxy curlimages/curl curl -X GET http://proxy:15001/delay/1
docker run -it --rm --link proxy curlimages/curl curl -X GET http://proxy:15001/delay/2
upstream request timeout

위와같이 현재 엔보이 프록시의 로그 설정을 확인할 수 있고 또 debug 모드로도 변경할 수 있다.

그리고 아까 타임아웃을 1초로 해둔 상태인데, delay를 0.5와 1초 했을 때의 결과를 다음과같이 확인 할 수 있다.

Envoy's Admin API를 사용하면 프록시 동작에 대해 이해할 수 있고 메트릭과 설정에 접근 할 수 있다.

docker run -it --rm --link proxy curlimages/curl curl -X GET http://proxy:15000/stats/prometheus # 엔보이 통계(프로메테우스 레코드 형식)

특히 위와같은 접근으로 프로메테우스 형식의 메트릭을 접근할 수 있다.

이를 활용하여 이스티오 관련 모니터링 대시보드를 만들 수 있을것이다. 예를들면 다음과 같다.

https://grafana.com/orgs/istio/dashboards

[istio Dashboards | Grafana Labs

uploaded on February 28, 2020 Downloads: 33513582 Reviews: 0

grafana.com](https://grafana.com/orgs/istio/dashboards)

docker rm -f proxy

#
cat ch3/simple_retry.yaml
docker run -p 15000:15000 --name proxy --link httpbin envoyproxy/envoy:v1.19.0 --config-yaml "$(cat ch3/simple_retry.yaml)"
docker run -it --rm --link proxy curlimages/curl curl -X POST http://proxy:15000/logging?http=debug

# /stats/500 경로로 프록시를 호출 : 이 경로로 httphbin 호출하면 오류가 발생
docker run -it --rm --link proxy curlimages/curl curl -X GET http://proxy:15001/status/500

# 호출이 끝났는데 아무런 응답도 보이지 않는다. 엔보이 Admin API에 확인
docker run -it --rm --link proxy curlimages/curl curl -X GET http://proxy:15000/stats | grep retry

위 스크립트는 1주차때 진행했던 500 에러 발생시 재시도 하는 테스트이다.

앞선 1주차때 했떤 이스티오 설정과 동일하게 엔보이에서도(당연히) 3회 시도에 대한 메트릭을 확인할 수 있다.

Summary

  • Envoy는 애플리케이션이 애플리케이션 수준의 동작에 사용할 수 있는 프록시입니다.
  • Envoy는 이스티오의 데이터 플레인입니다.
  • Envoy는 클라우드 신뢰성 문제(네트워크 장애, 토폴로지 변경, 탄력성)를 일관되고 정확하게 해결하는 데 도움을 줄 수 있습니다.
  • Envoy는 런타임 제어를 위해 동적 API를 사용합니다(Istio는 이를 사용합니다).
  • Envoy는 애플리케이션 사용 및 프록시 내부에 대한 강력한 지표와 정보를 많이 노출합니다.

istio 실습

실습 환경 구성

실제 실습을 진행하면서, 추가로 현재 운영중인 istio 환경도 함께 확인해볼 예정이다.

K8s 설치

#
git clone https://github.com/AcornPublishing/istio-in-action
cd istio-in-action/book-source-code-master
pwd # 각자 자신의 pwd 경로
code .

# 아래 extramounts 생략 시, myk8s-control-plane 컨테이너 sh/bash 진입 후 직접 git clone 가능
kind create cluster --name myk8s --image kindest/node:v1.23.17 --config - <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  extraPortMappings:
  - containerPort: 30000 # Sample Application (istio-ingrssgateway) HTTP
    hostPort: 30000
  - containerPort: 30001 # Prometheus
    hostPort: 30001
  - containerPort: 30002 # Grafana
    hostPort: 30002
  - containerPort: 30003 # Kiali
    hostPort: 30003
  - containerPort: 30004 # Tracing
    hostPort: 30004
  - containerPort: 30005 # Sample Application (istio-ingrssgateway) HTTPS
    hostPort: 30005
  - containerPort: 30006 # TCP Route
    hostPort: 30006
  - containerPort: 30007 # New Gateway 
    hostPort: 30007
  extraMounts: # 해당 부분 생략 가능
  - hostPath: /Users/gasida/Downloads/istio-in-action/book-source-code-master # 각자 자신의 pwd 경로로 설정
    containerPath: /istiobook
networking:
  podSubnet: 10.10.0.0/16
  serviceSubnet: 10.200.1.0/24
EOF

# 설치 확인
docker ps

# 노드에 기본 툴 설치
docker exec -it myk8s-control-plane sh -c 'apt update && apt install tree psmisc lsof wget bridge-utils net-tools dnsutils tcpdump ngrep iputils-ping git vim -y'

# (옵션) metrics-server
helm repo add metrics-server https://kubernetes-sigs.github.io/metrics-server/
helm install metrics-server metrics-server/metrics-server --set 'args[0]=--kubelet-insecure-tls' -n kube-system
kubectl get all -n kube-system -l app.kubernetes.io/instance=metrics-server

istio 설치

# myk8s-control-plane 진입 후 설치 진행
docker exec -it myk8s-control-plane bash
-----------------------------------
# (옵션) 코드 파일들 마운트 확인
tree /istiobook/ -L 1
혹은
git clone ... /istiobook

# istioctl 설치
export ISTIOV=1.17.8
echo 'export ISTIOV=1.17.8' >> /root/.bashrc

curl -s -L https://istio.io/downloadIstio | ISTIO_VERSION=$ISTIOV sh -
cp istio-$ISTIOV/bin/istioctl /usr/local/bin/istioctl
istioctl version --remote=false

# default 프로파일 컨트롤 플레인 배포
istioctl install --set profile=default -y

# 설치 확인 : istiod, istio-ingressgateway, crd 등
kubectl get istiooperators -n istio-system -o yaml
kubectl get all,svc,ep,sa,cm,secret,pdb -n istio-system
kubectl get cm -n istio-system istio -o yaml
kubectl get crd | grep istio.io | sort

# 보조 도구 설치
kubectl apply -f istio-$ISTIOV/samples/addons
kubectl get pod -n istio-system

# 빠져나오기
exit
-----------------------------------

# 실습을 위한 네임스페이스 설정
kubectl create ns istioinaction
kubectl label namespace istioinaction istio-injection=enabled
kubectl get ns --show-labels

# istio-ingressgateway 서비스 : NodePort 변경 및 nodeport 지정 변경 , externalTrafficPolicy 설정 (ClientIP 수집)
kubectl patch svc -n istio-system istio-ingressgateway -p '{"spec": {"type": "NodePort", "ports": [{"port": 80, "targetPort": 8080, "nodePort": 30000}]}}'
kubectl patch svc -n istio-system istio-ingressgateway -p '{"spec": {"type": "NodePort", "ports": [{"port": 443, "targetPort": 8443, "nodePort": 30005}]}}'
kubectl patch svc -n istio-system istio-ingressgateway -p '{"spec":{"externalTrafficPolicy": "Local"}}'
kubectl describe svc -n istio-system istio-ingressgateway

# NodePort 변경 및 nodeport 30001~30003으로 변경 : prometheus(30001), grafana(30002), kiali(30003), tracing(30004)
kubectl patch svc -n istio-system prometheus -p '{"spec": {"type": "NodePort", "ports": [{"port": 9090, "targetPort": 9090, "nodePort": 30001}]}}'
kubectl patch svc -n istio-system grafana -p '{"spec": {"type": "NodePort", "ports": [{"port": 3000, "targetPort": 3000, "nodePort": 30002}]}}'
kubectl patch svc -n istio-system kiali -p '{"spec": {"type": "NodePort", "ports": [{"port": 20001, "targetPort": 20001, "nodePort": 30003}]}}'
kubectl patch svc -n istio-system tracing -p '{"spec": {"type": "NodePort", "ports": [{"port": 80, "targetPort": 16686, "nodePort": 30004}]}}'

# Prometheus 접속 : envoy, istio 메트릭 확인
open http://127.0.0.1:30001

# Grafana 접속
open http://127.0.0.1:30002

# Kiali 접속 1 : NodePort
open http://127.0.0.1:30003

# (옵션) Kiali 접속 2 : Port forward
kubectl port-forward deployment/kiali -n istio-system 20001:20001 &
open http://127.0.0.1:20001

# tracing 접속 : 예거 트레이싱 대시보드
open http://127.0.0.1:30004


# 접속 테스트용 netshoot 파드 생성
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: netshoot
spec:
  containers:
  - name: netshoot
    image: nicolaka/netshoot
    command: ["tail"]
    args: ["-f", "/dev/null"]
  terminationGracePeriodSeconds: 0
EOF

실습 진행

이스티오 인그레스 게이트웨이는 클러스터 외부에서 내부로 들어오는 트래픽의 진입점을 제어하는 역할을 한다. 인그레스 게이트웨이는 Envoy 프록시 기반의 로드밸런서로 동작하며, 외부 트래픽을 받아 필요한 포트와 프로토콜을 지정해 노출한다. 하지만 실제 트래픽 라우팅(어떤 서비스로 전달할지)은 VirtualService 리소스를 통해 L7(애플리케이션 레이어)에서 세밀하게 제어한다.

즉, Gateway는 L4/L5 계층에서 트래픽을 받아들이고, VirtualService는 L7 계층에서 트래픽의 목적지와 라우팅 정책을 결정한다. 이 구조를 통해 이스티오는 외부 트래픽의 보안, 로드밸런싱, 가상 호스트 라우팅 등 다양한 네트워크 기능을 유연하게 제공한다.

현재 운영중인 istio 환경 정보

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: live-ops-query-gateway
  namespace: istio-system
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "ops-query.test.co.kr"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ops-query-vs
  namespace: devops
spec:
  hosts:
  - "ops-query.test.co.kr"
  gateways:
  - istio-system/live-ops-query-gateway
  http:
  - match:
    - uri:
        prefix: /
    route:
    - destination:
        host: ops-query-svc-active
      weight: 100
    - destination:
        host: ops-query-svc-preview
      weight: 0

 

 

아래는 실습환경이다.

404 에러가 발생한다. 이는 host 헤더가 알맞지 않아서 발생하는 문제이다.

 

헤더 수정후 다시 입력하면 정상적으로 응답되는것을 알 수 있다.

 

 

securing gateway traffic 실습

실무환경에서는 앞단의 ALB에 인증서만 적용해두고 내부의 이스티오간 인증서는 적용돼있지 않은상태다. 추후 보안심사때 문제가 발생하면 그때 적용해야겠다....

 

어쨋든.. 실습 환경에서 현재 적용 돼 있는 인증서는 다음과 같다.

kubectl create -n istio-system secret tls webapp-credential \
--key ch4/certs/3_application/private/webapp.istioinaction.io.key.pem \
--cert ch4/certs/3_application/certs/webapp.istioinaction.io.cert.pem

 kubectl apply -f ch4/coolstore-gw-tls.yaml -n istioinaction

 

이제 위 명령어로 시크릿을 만들고 게이트웨이를 재배포한다.

 

그러면 위와같이 새로운 인증서가 추가된것을 볼 수 있다.

그리고 curl 로 접속 테스트를 하면 에러가 나는것을 볼 수 있다.

 

이는 서버(istio-ingressgateway 파드)에서 제공하는 인증서는 기본 CA 인증서 체인을 사용해 확인할 수 없다는 의미다.

다시  cacert 옵션을 줘서 테스트를 한다. 또 에러가 난다. 이번엔 Local host로 접속해서 발생한 문제이다.

 

echo "127.0.0.1       webapp.istioinaction.io" | sudo tee -a /etc/hosts

위 명령어를 입력해서 임시로 dns 를 설정해준다.

 

다시 호출 테스트를 진행하면 정상적으로 접속되는것을 알 수 있다.

 

 

이번에는 https만 사용하도록 하는 리다이렉트 설정이다.

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: coolstore-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "webapp.istioinaction.io"
    tls:
      httpsRedirect: true 
  - port:
      number: 443
      name: https
      protocol: HTTPS
    tls:
      mode: SIMPLE
      credentialName: webapp-credential
    hosts:
    - "webapp.istioinaction.io"

 

 

이번엔  mTLS이다.

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: coolstore-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "webapp.istioinaction.io"
  - port:
      number: 443
      name: https
      protocol: HTTPS
    tls:
      mode: MUTUAL # mTLS 설정
      credentialName: webapp-credential-mtls # 신뢰할 수 있는 CA가 구성된 자격 증명
    hosts:
    - "webapp.istioinaction.io"

 

다음과 같이 클라이언트 인증서 없이 에러가 발생한다.

 

 

클라이언트 인증서를 명시하면 정상적으로 동작하는것을 알 수 있다.

 

 

Serving multiple virtual hosts with TLS

이스티오 인그레스 게이트웨이는 동일한 HTTPS 포트(443)에서 각기 다른 인증서와 비밀 키를 사용해 여러 도메인(가상 호스트)의 트래픽을 동시에 처리할 수 있다.

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: coolstore-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 443
      name: https-webapp
      protocol: HTTPS
    tls:
      mode: SIMPLE
      credentialName: webapp-credential
    hosts:
    - "webapp.istioinaction.io"
  - port:
      number: 443
      name: https-catalog
      protocol: HTTPS
    tls:
      mode: SIMPLE
      credentialName: catalog-credential
    hosts:
    - "catalog.istioinaction.io"

두개의 버추어 서비스를 처리하는것을 확인 할 수 있다. 이를 처리하는 플로우는 클라이언트가 게이트웨이(엔보이)로 HTTPS 연결을 시작하면, TLS 핸드셰이크의 ClientHello 단계에서 SNI(서버 이름 표시) 확장에 접근하려는 서비스의 도메인을 명시해 전달하고, 엔보이는 이 SNI 정보를 기반으로 올바른 인증서를 선택해 제시하고 해당 서비스로 트래픽을 라우팅한다.

 

TCP 트래픽에 대한 실습이다.

이스티오 게이트웨이는 TCP 기반 서비스도 외부에 노출할 수 있지만, HTTP처럼 세밀한 트래픽 제어나 고급 기능은 사용할 수 없다.
이는 엔보이가 프로토콜을 이해하지 못해 단순 TCP 프록시만 가능하기 때문이다.
클러스터 외부에서 내부 TCP 서비스를 이용하려면 게이트웨이에서 해당 포트를 노출하면 된다.

#
cat ch4/echo.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: tcp-echo-deployment
  labels:
    app: tcp-echo
    system: example
spec:
  replicas: 1
  selector:
    matchLabels:
      app: tcp-echo
  template:
    metadata:
      labels:
        app: tcp-echo
        system: example
    spec:
      containers:
        - name: tcp-echo-container
          image: cjimti/go-echo:latest
          imagePullPolicy: IfNotPresent
          env:
            - name: TCP_PORT
              value: "2701"
            - name: NODE_NAME
              valueFrom:
                fieldRef:
                  fieldPath: spec.nodeName
            - name: POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: POD_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
            - name: POD_IP
              valueFrom:
                fieldRef:
                  fieldPath: status.podIP
            - name: SERVICE_ACCOUNT
              valueFrom:
                fieldRef:
                  fieldPath: spec.serviceAccountName
          ports:
            - name: tcp-echo-port
              containerPort: 2701
---
apiVersion: v1
kind: Service
metadata:
  name: "tcp-echo-service"
  labels:
    app: tcp-echo
    system: example
spec:
  selector:
    app: "tcp-echo"
  ports:
    - protocol: "TCP"
      port: 2701
      targetPort: 2701

kubectl apply -f ch4/echo.yaml -n istioinaction

#
kubectl get pod -n istioinaction
NAME                                   READY   STATUS    RESTARTS   AGE
tcp-echo-deployment-584f6d6d6b-xcpd8   2/2     Running   0          27s
...

 

# tcp 서빙 포트 추가 : 편집기는 vi 대신 nano 선택 <- 편한 툴 사용
KUBE_EDITOR="nano"  kubectl edit svc istio-ingressgateway -n istio-system
...
  - name: tcp
    nodePort: 30006
    port: 31400
    protocol: TCP
    targetPort: 31400
...

# 확인
kubectl get svc istio-ingressgateway -n istio-system -o jsonpath='{.spec.ports[?(@.name=="tcp")]}'
{"name":"tcp","nodePort":30006,"port":31400,"protocol":"TCP","targetPort":31400}


# 게이트웨이 생성
cat ch4/gateway-tcp.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: echo-tcp-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 31400
      name: tcp-echo
      protocol: TCP
    hosts:
    - "*"
    
kubectl apply -f ch4/gateway-tcp.yaml -n istioinaction
kubectl get gw -n istioinaction

# 에코 서비스로 라우팅하기 위해 VirtualService 리소스 생성
cat ch4/echo-vs.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: tcp-echo-vs-from-gw
spec:
  hosts:
  - "*"
  gateways:
  - echo-tcp-gateway
  tcp:
  - match:
    - port: 31400
    route:
    - destination:
        host: tcp-echo-service
        port:
          number: 2701

#
kubectl apply -f ch4/echo-vs.yaml -n istioinaction
kubectl get vs -n istioinaction
NAME                  GATEWAYS                HOSTS                          AGE
catalog-vs-from-gw    ["coolstore-gateway"]   ["catalog.istioinaction.io"]   44m
tcp-echo-vs-from-gw   ["echo-tcp-gateway"]    ["*"]                          6s
webapp-vs-from-gw     ["coolstore-gateway"]   ["webapp.istioinaction.io"]    3h59m


# mac 에 telnet 설치
brew install telnet

#
telnet localhost 30006
Trying ::1...
Connected to localhost.
Escape character is '^]'.
Welcome, you are connected to node myk8s-control-plane.
Running on Pod tcp-echo-deployment-584f6d6d6b-xcpd8.
In namespace istioinaction.
With IP address 10.10.0.20.
Service default.
hello istio! # <-- type here
hello istio! # <-- echo here

# telnet 종료하기 : 세션종료 Ctrl + ] > 텔넷 종료 quit

 

 

 

SNI passthrough 실습

이스티오 인그레스 게이트웨이는 TLS 연결을 종료하지 않고 SNI 호스트네임을 기반으로 TCP 트래픽을 라우팅하며, 백엔드 서비스에서 TLS 처리를 담당함으로써 다양한 레거시 애플리케이션 및 TCP 서비스를 서비스 메시에 통합할 수 있다.

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: sni-passthrough-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 31400 #1 HTTP 포트가 아닌 특정 포트 열기
      name: tcp-sni
      protocol: TLS
    hosts:
    - "simple-sni-1.istioinaction.io" #2 이 호스트를 포트와 연결
    tls:
      mode: PASSTHROUGH #3 통과 트래픽으로 처리

 

# TLS 인증을 직접 처리하는 앱 배포. (gw는 route 만 처리, pass through )
cat ch4/sni/simple-tls-service-1.yaml
kubectl apply -f ch4/sni/simple-tls-service-1.yaml -n istioinaction
kubectl get pod -n istioinaction

# 기존 Gateway 명세(echo-tcp-gateway) 제거 : istio-ingressgateway의 동일한 port (31400, TCP)를 사용하므로 제거함
kubectl delete gateway echo-tcp-gateway -n istioinaction

# 신규 Gateway 설정
kubectl apply -f ch4/sni/passthrough-sni-gateway.yaml -n istioinaction
kubectl get gw -n istioinaction

 

# 두 번째 서비스 배포
cat ch4/sni/simple-tls-service-2.yaml
kubectl apply -f ch4/sni/simple-tls-service-2.yaml -n istioinaction

# gateway 설정 업데이트
cat ch4/sni/passthrough-sni-gateway-both.yaml
kubectl apply -f ch4/sni/passthrough-sni-gateway-both.yaml -n istioinaction

# VirtualService 설정
cat ch4/sni/passthrough-sni-vs-2.yaml
kubectl apply -f ch4/sni/passthrough-sni-vs-2.yaml -n istioinaction

# 호출테스트2
echo "127.0.0.1       simple-sni-2.istioinaction.io" | sudo tee -a /etc/hosts

curl https://simple-sni-2.istioinaction.io:30006 \
--cacert ch4/sni/simple-sni-2/2_intermediate/certs/ca-chain.cert.pem

 

 

Split gateway responsibilities 실습

여러 인그레스 게이트웨이를 배포하면 서비스별 요구사항이나 팀별로 트래픽 경로와 설정을 독립적으로 관리·격리할 수 있다.

apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
  name: my-user-gateway-install
  namespace: istioinaction
spec:
  profile: empty
  values:
    gateways:
      istio-ingressgateway:
        autoscaleEnabled: false
  components:
    ingressGateways:
    - name: istio-ingressgateway
      enabled: false    
    - name: my-user-gateway
      namespace: istioinaction
      enabled: true
      label:
        istio: my-user-gateway
      k8s:
        service:
          ports:
            - name: tcp  # my-user-gateway 에서 사용할 포트 설정
              port: 30007
              targetPort: 31400
#
docker exec -it myk8s-control-plane bash
------------------------------------------
# istioinaction 네임스페이스에 Ingress gateway 설치
cat <<EOF > my-user-gateway-edited.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
  name: my-user-gateway-install
  namespace: istioinaction
spec:
  profile: empty
  values:
    gateways:
      istio-ingressgateway:
        autoscaleEnabled: false
  components:
    ingressGateways:
    - name: istio-ingressgateway
      enabled: false    
    - name: my-user-gateway
      namespace: istioinaction
      enabled: true
      label:
        istio: my-user-gateway
      k8s:
        service:
          ports:
            - name: tcp  # my-user-gateway 에서 사용할 포트 설정
              port: 31400
              targetPort: 31400
              nodePort: 30007 # 외부 접속을 위해 NodePort Number 직접 설정
EOF

# istioctl manifest generate -n istioinaction -f my-user-gateway-edited.yaml
istioctl install -y -n istioinaction -f my-user-gateway-edited.yaml

exit
------------------------------------------

# IstioOperator 확인
kubectl get IstioOperator -A
NAMESPACE       NAME                      REVISION   STATUS   AGE
istio-system    installed-state                               5h48m
istioinaction   my-user-gateway-install                       17s

#
kubectl get deploy my-user-gateway -n istioinaction
NAME              READY   UP-TO-DATE   AVAILABLE   AGE
my-user-gateway   1/1     1            1           65s

# 포트 확인
kubectl get svc my-user-gateway -n istioinaction -o yaml
...
  - name: tcp
    nodePort: 30007
    port: 31400
    protocol: TCP
    targetPort: 31400
...

 

 

 

Gateway injection

게이트웨이 주입(gateway injection)을 사용하면, 사용자가 IstioOperator 리소스 전체 권한 없이도 미완성(서브된) 게이트웨이 Deployment 리소스를 배포할 수 있고, Istio가 나머지 설정을 자동으로 채워준다. 이 방식은 사이드카 주입과 유사하게, 각 팀이 필요한 최소한의 리소스만 정의하면 Istio가 필요한 프록시와 설정을 자동으로 붙여준다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-user-gateway-injected
  namespace: istioinaction
spec:
  selector:
    matchLabels:
      ingress: my-user-gateway-injected
  template:
    metadata:
      annotations:
        sidecar.istio.io/inject: "true" #1 주입 활성화
        inject.istio.io/templates: gateway #2 gateweay 템플릿  
      labels:
        ingress: my-user-gateway-injected
    spec:
      containers:
      - name: istio-proxy #3 반드시 이 이름이어야 한다
        image: auto #4 미완성 이미지
...

 

Ingress gateway access logs 실습

이스티오 데모 프로필에서는 엔보이 프록시의 액세스 로그가 표준 출력으로 기록되어 컨테이너 로그를 통해 쉽게 확인할 수 있다.

#
kubectl get cm -n istio-system istio -o yaml
data:
  mesh: |-
    defaultConfig:
      discoveryAddress: istiod.istio-system.svc:15012
      proxyMetadata: {}
      tracing:
        zipkin:
          address: zipkin.istio-system:9411
    enablePrometheusMerge: true
    rootNamespace: istio-system
    trustDomain: cluster.local
  meshNetworks: 'networks: {}'
..

#
docker exec -it myk8s-control-plane bash
------------------------------------------
# 표준 출력 스트림으로 출력하도록 accessLogFile 속성을 변경
istioctl install --set meshConfig.accessLogFile=/dev/stdout
y 입력

exit
------------------------------------------

# configmap 에 mesh 바로 아래에 accessLogFile 부분 추가됨
kubectl get cm -n istio-system istio -o yaml
...
  mesh: |-
    accessLogFile: /dev/stdout
...

# 애플리케이션 호출에 대한 로그도 출력됨!
kubectl stern -n istioinaction -l app=webapp -c istio-proxy
webapp-7685bcb84-h5knf istio-proxy [2025-04-14T09:30:47.764Z] "GET /items HTTP/1.1" 200 - via_upstream - "-" 0 502 1 1 "172.18.0.1" "beegoServer" "4c10dba4-f49a-4b58-9805-ac30515dd417" "catalog.istioinaction:80" "10.10.0.8:3000" outbound|80||catalog.istioinaction.svc.cluster.local 10.10.0.9:60052 10.200.1.251:80 172.18.0.1:0 - default
webapp-7685bcb84-h5knf istio-proxy [2025-04-14T09:30:48.805Z] "GET /items HTTP/1.1" 200 - via_upstream - "-" 0 502 6 6 "172.18.0.1" "beegoServer" "7733f4d0-6e3a-4138-a126-fe25c30e51f4" "catalog.istioinaction:80" "10.10.0.8:3000" outbound|80||catalog.istioinaction.svc.cluster.local 10.10.0.9:60898 10.200.1.251:80 172.18.0.1:0 - default
...

운영 환경에서는 트래픽과 로그량이 많기 때문에, 텔레메트리 API를 이용해 필요한 워크로드에만 액세스 로그를 selectively 활성화하는 것이 효율적이다.

apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
  name: ingress-gateway
  namespace: istio-system
spec:
  selector:
    matchLabels:
      app: istio-ingressgateway #1 레이블과 일치하는 파드는 텔레메트리 설정을 가져온다
  accessLogging:
  - providers:
    - name: envoy #2 액세스 로그를 위한 프로바이더 설정
    disabled: false #3 disable 를 false 로 설정해 활성화한다

 

Reducing gateway configuration

이스티오는 기본적으로 모든 프록시가 메시 내 모든 서비스를 알도록 설정되어 있어 서비스가 많아지면 프록시 설정이 비대해지고 성능 및 확장성 문제가 발생할 수 있다. 이를 해결하기 위해 게이트웨이 프록시에는 필요한 설정만 포함하도록 "게이트웨이 설정 잘라내기" 기능을 명시적으로 활성화할 수 있다.

개인적으로 오늘 스터디에서 배운것중 가장 필요했던것이다. 일전에 istio 설정 잘못해서 서비스 연결이 제대로 안됐었는데, 디버깅 하기가 너무 힘들었다. 해당 설정때문에 앞으로 좀 더 수월해질듯 하다.

apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
  name: control-plane
spec:
  profile: minimal
  components:
    pilot:
      k8s:
        env:
        - name: PILOT_FILTER_GATEWAY_CLUSTER_CONFIG
          value: "true"
  meshConfig:
    defaultConfig:
      proxyMetadata:
        ISTIO_META_DNS_CAPTURE: "true"
    enablePrometheusMerge: true

'job > devops' 카테고리의 다른 글

istio-1  (0) 2025.04.08
taskfile  (0) 2024.03.10
kubewarden  (0) 2024.01.20
openfunction  (0) 2023.12.01
git common flow(또는 gitlab flow) 브랜치 전략에 대한 설명  (0) 2023.06.13

사내에서 istio 프록시로 구성하여 사용중인데, 뭐랄까. 제대로 못쓰고 있는듯하다. 굳이 istio를 붙인것같은.. 제대로 못쓸꺼면 아에 빼버리던가(네트워크 문제시 파악 구간이 더 많아져서 싫다.) 아니면 제대로 쓸 수 있는 실력이 필요했다. 예를들어, 서비스 장애가 발생할 경우 istio가 없었다면 단순히 네트워크 구간만 살펴보면 됐다. 그런데 현재는 istio 구간까지 추가로 살펴봐야 한다. 문제는 해당 구간에 대한 모니터링이 안되고 있는 상황. 그래서 명확히 이 구간은 문제가 없다라고 판단하기가 어렵다. 이를 해결하려면 istio에 빠삭히 알아야 할 것 같았다. 그래서 작년에 istio 시험을 사두기만 했다. 그렇게 시간을 보내다 때마침 가시다님께서 istio 스터디를 진행하신다기에 재빨리 신청했다. (과거 여러 스터디를 운영하셨던 분들을 포함한 가시다님, 김원일님, 김석필님 감사합니다.)

스터디를 끝낼 때 istio 운영을 유지하며 시스템을 더욱 고도화(모니터링 추가등)할 지, 아니면 istio를 걷어낼지를 판단 할 수 있는 실력이 쌓였으면 좋겠다.

현재 사내에 istio를 사용중이다. 따라서 실습하면서 실제 운영환경과 비교하고 다른점이 있다면 어떤 설정에 의해 왜 다른지도 다뤄보고자 한다.

그럼 1주차 시작

Istio에 대한 간략한 설명

Istio를 왜 사용해야 하는가 ? Istio를 사용하지 않을 경우 발생할 수 있는 문제.

서비스 간 통신의 복잡성 증가:
네트워크 장애, 과부하, 버그 등으로 인해 서비스 간 요청이 실패하거나 성능 저하가 발생할 수 있음.
예를 들어, 다운스트림 서비스가 느리거나 장애가 발생하면 연쇄적인 서비스 장애로 이어질 가능성이 큼.

복원력 패턴 구현의 어려움:
타임아웃, 재시도, 서킷 브레이커 등의 복원력 패턴을 각 애플리케이션에서 직접 구현해야 함.
여러 언어와 프레임워크를 사용하는 환경에서는 이러한 패턴을 일관되게 구현하기 어려움.

운영 및 유지보수 부담 증가:
라이브러리 의존성을 관리하고 각 애플리케이션에 맞게 코드를 수정해야 하며, 이는 시간이 많이 소요되고 오류 가능성을 높임.
새로운 언어나 프레임워크 도입 시 추가적인 구현 작업이 필요함.

관찰 가능성 부족:
서비스 간 트래픽, 요청 실패율, 성능 병목 등을 실시간으로 파악하기 어려움.
장애 원인을 추적하거나 시스템 상태를 모니터링하는 데 한계가 있음.

Istio를 사용하면 해결되는 점

서비스 간 통신의 표준화:
Istio는 Envoy 프록시를 통해 서비스 간 통신을 관리하며, 재시도, 타임아웃, 서킷 브레이커 등의 기능을 애플리케이션 외부에서 제공.
이를 통해 서비스 간 통신의 안정성과 복원력을 높일 수 있음.

언어 및 프레임워크 독립성:
애플리케이션 코드 수정 없이 네트워크 관련 기능을 제공하므로 언어나 프레임워크에 구애받지 않음.
다양한 기술 스택에서도 일관된 네트워킹 정책 적용 가능.

운영 부담 감소:
Istio가 네트워킹 및 보안 정책을 중앙에서 관리하므로 각 애플리케이션에서 이를 구현할 필요가 없음.
새로운 서비스 추가나 변경 시에도 운영 부담이 줄어듦.

강화된 관찰 가능성:
Istio는 메트릭, 로그, 분산 트레이싱을 통해 실시간으로 시스템 상태를 모니터링 가능.
장애 원인 분석 및 성능 최적화 작업이 용이해짐.

결론
Istio는 네트워킹 관련 문제를 애플리케이션에서 인프라로 전가(내가 생각하는 devops 엔지니어는, 개발자는 회사의 이익에 필요한 개발만 할 수 있도록 환경을 만들어주는거라 생각하는데.. 이 모토랑 일치하는듯)하여 운영 효율성을 높이고, 복잡한 클라우드 환경에서도 안정적으로 서비스를 운영할 수 있도록 돕습니다.

Istio란? 서비스메시란 ? 엔보이프록시? 사이드카?

서비스 메시 (Service Mesh)

서비스 메시란, 여러 서비스가 서로 대화할 때 그 대화를 도와주는 네트워크의 "통신 감독관" 같은 역할을 합니다.
예를 들어, 학교에서 선생님이 학생들끼리 조용히 대화하도록 도와주는 것과 비슷합니다.

엔보이 프록시 (Envoy Proxy)

엔보이 프록시는 서비스들 사이에서 주고받는 메시지를 대신 전달하는 "우체부" 역할을 합니다.
예를 들어, 친구에게 편지를 보낼 때 우체부가 대신 전달해 주는 것처럼, 엔보이는 서비스 간 데이터를 안전하고 빠르게 전달합니다.

사이드카 (Sidecar)

사이드카는 주 컨테이너(주요 프로그램)를 도와주는 "조수" 컨테이너입니다.
예를 들어, 오토바이에 붙어 있는 작은 캐빈처럼, 사이드카는 옆에서 필요한 일을 돕습니다. Istio에서는 이 사이드카가 엔보이 프록시로 동작합니다.

Istio 프록시

Istio 프록시는 엔보이 프록시를 사용하여 각 서비스 옆에 사이드카로 배치됩니다.
예를 들어, 학교에서 각 반마다 선생님(프록시)이 배치되어 학생들(서비스)이 서로 잘 소통하도록 돕는 것과 같습니다. 이 프록시는 메시지를 가로채고, 어디로 보내야 할지 알려주며, 보안도 책임집니다.

연관 관계

  • 서비스 메시 안에는 여러 서비스가 있고, 이들이 서로 대화할 때 엔보이 프록시가 중간에서 도와줍니다.
  • 엔보이 프록시는 각 서비스 옆에 사이드카 형태로 배치되어 Istio라는 시스템의 일부로 작동합니다.
  • Istio는 전체 네트워크를 관리하며 트래픽을 안전하고 효율적으로 제어합니다.

즉 정리하자면, Istio를 사용하지 않는다면 애플리케이션 레벨에서의 리소스가 많이 사용되는데, Istio를 사용하면 효율적으로 인프라 레벨로 옮길 수 있다. 어떻게? 사이드카 프록시로.

Istio의 단점은 ?

디버깅 복잡성 증가

Envoy 프록시가 추가되면서 네트워크 요청 경로가 복잡해지고, 프록시에 익숙하지 않은 경우 디버깅이 어려워질 수 있음.

테넌시 관리의 어려움
서비스 메시 구성 시 적절한 정책과 자동화가 없으면 잘못된 설정으로 인해 다수의 서비스에 영향을 미칠 가능성이 있음.

운영 복잡성 증가
서비스 메시 도입으로 새로운 레이어가 추가되어 시스템 아키텍처와 운영 절차가 복잡해질 수 있음.

조직의 기존 거버넌스 및 팀 간 협업과의 통합이 어려울 수 있음.

실습 진행

istio 설치

$ istioctl version --remote=false
$ kubectl get all,svc,ep,sa,cm,secret,pdb -n istio-system
NAME                                       READY   STATUS    RESTARTS   AGE
pod/grafana-b854c6c8-rhsvm                 1/1     Running   0          19h
pod/istio-ingressgateway-996bc6bb6-lwqq5   1/1     Running   0          19h
pod/istiod-7df6ffc78d-r4jvv                1/1     Running   0          19h
pod/jaeger-5556cd8fcf-8z2zz                1/1     Running   0          19h
pod/kiali-648847c8c4-wcw8l                 1/1     Running   0          19h
pod/prometheus-7b8b9dd44c-zzsr8            2/2     Running   0          19h

NAME                           TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)                                      AGE
service/grafana                ClusterIP      10.200.1.30    <none>        3000/TCP                                     19h
service/istio-ingressgateway   LoadBalancer   10.200.1.103   <pending>     15021:31155/TCP,80:30491/TCP,443:30079/TCP   19h
service/istiod                 ClusterIP      10.200.1.116   <none>        15010/TCP,15012/TCP,443/TCP,15014/TCP        19h
service/jaeger-collector       ClusterIP      10.200.1.31    <none>        14268/TCP,14250/TCP,9411/TCP                 19h
service/kiali                  ClusterIP      10.200.1.99    <none>        20001/TCP,9090/TCP                           19h
service/prometheus             ClusterIP      10.200.1.130   <none>        9090/TCP                                     19h
service/tracing                ClusterIP      10.200.1.38    <none>        80/TCP,16685/TCP                             19h
service/zipkin                 ClusterIP      10.200.1.200   <none>        9411/TCP                                     19h

NAME                                   READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/grafana                1/1     1            1           19h
deployment.apps/istio-ingressgateway   1/1     1            1           19h
deployment.apps/istiod                 1/1     1            1           19h
deployment.apps/jaeger                 1/1     1            1           19h
deployment.apps/kiali                  1/1     1            1           19h
deployment.apps/prometheus             1/1     1            1           19h

NAME                                             DESIRED   CURRENT   READY   AGE
replicaset.apps/grafana-b854c6c8                 1         1         1       19h
replicaset.apps/istio-ingressgateway-996bc6bb6   1         1         1       19h
replicaset.apps/istiod-7df6ffc78d                1         1         1       19h
replicaset.apps/jaeger-5556cd8fcf                1         1         1       19h
replicaset.apps/kiali-648847c8c4                 1         1         1       19h
replicaset.apps/prometheus-7b8b9dd44c            1         1         1       19h

NAME                                                       REFERENCE                         TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
horizontalpodautoscaler.autoscaling/istio-ingressgateway   Deployment/istio-ingressgateway   8%/80%    1         5         1          19h
horizontalpodautoscaler.autoscaling/istiod                 Deployment/istiod                 0%/80%    1         5         1          19h

NAME                             ENDPOINTS                                                     AGE
endpoints/grafana                10.10.0.10:3000                                               19h
endpoints/istio-ingressgateway   10.10.0.8:15021,10.10.0.8:8080,10.10.0.8:8443                 19h
endpoints/istiod                 10.10.0.7:15012,10.10.0.7:15010,10.10.0.7:15017 + 1 more...   19h
endpoints/jaeger-collector       10.10.0.9:9411,10.10.0.9:14250,10.10.0.9:14268                19h
endpoints/kiali                  10.10.0.11:9090,10.10.0.11:20001                              19h
endpoints/prometheus             10.10.0.12:9090                                               19h
endpoints/tracing                10.10.0.9:16685,10.10.0.9:16686                               19h
endpoints/zipkin                 10.10.0.9:9411                                                19h

NAME                                                  SECRETS   AGE
serviceaccount/default                                1         19h
serviceaccount/grafana                                1         19h
serviceaccount/istio-ingressgateway-service-account   1         19h
serviceaccount/istio-reader-service-account           1         19h
serviceaccount/istiod                                 1         19h
serviceaccount/istiod-service-account                 1         19h
serviceaccount/kiali                                  1         19h
serviceaccount/prometheus                             1         19h

NAME                                            DATA   AGE
configmap/grafana                               4      19h
configmap/istio                                 2      19h
configmap/istio-ca-root-cert                    1      19h
configmap/istio-gateway-deployment-leader       0      19h
configmap/istio-gateway-status-leader           0      19h
configmap/istio-grafana-dashboards              2      19h
configmap/istio-leader                          0      19h
configmap/istio-namespace-controller-election   0      19h
configmap/istio-services-grafana-dashboards     4      19h
configmap/istio-sidecar-injector                2      19h
configmap/kiali                                 1      19h
configmap/kube-root-ca.crt                      1      19h
configmap/prometheus                            5      19h

NAME                                                      TYPE                                  DATA   AGE
secret/default-token-lmqrr                                kubernetes.io/service-account-token   3      19h
secret/grafana-token-74qt2                                kubernetes.io/service-account-token   3      19h
secret/istio-ca-secret                                    istio.io/ca-root                      5      19h
secret/istio-ingressgateway-service-account-token-tlq54   kubernetes.io/service-account-token   3      19h
secret/istio-reader-service-account-token-8zz99           kubernetes.io/service-account-token   3      19h
secret/istiod-service-account-token-zrr8b                 kubernetes.io/service-account-token   3      19h
secret/istiod-token-x64kr                                 kubernetes.io/service-account-token   3      19h
secret/kiali-token-84msl                                  kubernetes.io/service-account-token   3      19h
secret/prometheus-token-vqmbw                             kubernetes.io/service-account-token   3      19h

NAME                                              MIN AVAILABLE   MAX UNAVAILABLE   ALLOWED DISRUPTIONS   AGE
poddisruptionbudget.policy/istio-ingressgateway   1               N/A               0                     19h
poddisruptionbudget.policy/istiod                 1               N/A               0                     19h

이중 istio-ingressgateway 서비스 리소스의 경우 실제 운영환경은 다음과 같이 EXTERNAL-IP에 CSP의 LB 도메인이 들어가있다. 실습 환경에서는 PENDING이다.

$ k get svc -n istio-system
NAME                   TYPE           CLUSTER-IP       EXTERNAL-IP                                                                   PORT(S)                                      AGE
istio-ingressgateway   LoadBalancer   198.19.240.44    istio-syste-istio-ingres-xxx.kr-fin.lb.naverncp.com   15021:31396/TCP,80:30616/TCP,443:31295/TCP   527d
istiod                 ClusterIP      198.19.157.147   <none>                                                                        15010/TCP,15012/TCP,443/TCP,15014/TCP        527d

이는 CSP(NCP)에서 설치된 쿠버네티스 클러스터(NKS)에는 기본적으로 cloud controller manager의 service controller에 의해 자동으로 NKS의 LB를 생성한다. 관련 설정은 kube-system 네임스페이스에 ncloud-config라는 ConfigMap이 적용 돼 있다.

$ k get cm -n kube-system -o yaml ncloud-config
apiVersion: v1
data:
  acgNo: "11111"
  apiUrl: https://nks.apigw.fin-ntruss.com
  basePath: /ncloud-api/v1
  clusterId: "1111"
  lbPublicSubnetNo: "11111"
  lbSubnetNo: "11111"
  regionCode: FKR
  regionNo: "1"
  vpcNo: "1111"
  zoneNo: "111"
kind: ConfigMap
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
생략
  creationTimestamp: "2023-10-30T02:09:49Z"
  name: ncloud-config
  namespace: kube-system
  resourceVersion: "1111111"
  uid: 11111-1a71-457e-813c-4b2d13f00446

해당 설정에 의해 서비스타입이 로드밸런서인경우 NCP API와 상호작용하여, 자동으로 NCP의 LB(기본값은 프록시 로드밸런서)를 생성하게 된다.
참고로 로드밸런서 이름(익스터널IP에 들어가는 도메인명)의 생성 규칙은 다음과 같다.
<네임스페이스-서비스이름-포트번호-랜덤문자열>

파드배포(사이드카로 Istio 도 같이 배포)

이제 배포되는 모든 파드들에 사이드카로 istio가 같이 배포되도록 해야 한다. 이는 2가지 방법이 있는데,
docker exec -it myk8s-control-plane istioctl kube-inject -f /istiobook/services/catalog/kubernetes/catalog.yaml
으로 매니페스트에 사이드카 설정을 추가하는 방법과

kubectl label namespace istioinaction istio-injection=enabled
으로, 네임스페이스에 istio-injection=enabled Label에 설정 돼 있는 경우 해당 네임스페이스의 파드 스펙에 자동으로 사이드카 설정을 한다.

이제 파드를 배포하면 다음과 같이 앱이 배포된다.

하나의 파드에 두개의 컨테이너가 있음이 확인된다. 이를 describe로 확인해보면 보는것처럼 catalog라는 메인 컨테이너외에 istio-proxy라는 사이드카 컨테이너가 올라온것을 알 수 있다.

istio proxy 상태 확인

# istioctl proxy-status : 단축어 ps
docker exec -it myk8s-control-plane istioctl proxy-status
NAME                                                  CLUSTER        CDS        LDS        EDS        RDS        ECDS         ISTIOD                      VERSION
catalog-6cf4b97d-nccfj.istioinaction                  Kubernetes     SYNCED     SYNCED     SYNCED     SYNCED     NOT SENT     istiod-7df6ffc78d-bj7h7     1.17.8
istio-ingressgateway-996bc6bb6-mz544.istio-system     Kubernetes     SYNCED     SYNCED     SYNCED     SYNCED     NOT SENT     istiod-7df6ffc78d-bj7h7     1.17.8
webapp-7685bcb84-c55ck.istioinaction                  Kubernetes     SYNCED     SYNCED     SYNCED     SYNCED     NOT SENT     istiod-7df6ffc78d-bj7h7     1.17.8

ISTIOIGW=istio-ingressgateway-996bc6bb6-647tx.istio-system
WEBAPP=webapp-7685bcb84-nfntj.istioinaction

# istioctl proxy-config : 단축어 pc
docker exec -it myk8s-control-plane istioctl proxy-config all $ISTIOIGW
docker exec -it myk8s-control-plane istioctl proxy-config all $WEBAPP

docker exec -it myk8s-control-plane istioctl proxy-config listener $ISTIOIGW
docker exec -it myk8s-control-plane istioctl proxy-config route $ISTIOIGW
docker exec -it myk8s-control-plane istioctl proxy-config cluster $ISTIOIGW
docker exec -it myk8s-control-plane istioctl proxy-config endpoint $ISTIOIGW
docker exec -it myk8s-control-plane istioctl proxy-config log $ISTIOIGW

docker exec -it myk8s-control-plane istioctl proxy-config listener $WEBAPP
docker exec -it myk8s-control-plane istioctl proxy-config route $WEBAPP
docker exec -it myk8s-control-plane istioctl proxy-config cluster $WEBAPP
docker exec -it myk8s-control-plane istioctl proxy-config endpoint $WEBAPP
docker exec -it myk8s-control-plane istioctl proxy-config log $WEBAPP

# envoy 가 사용하고 있는 인증서 정보 확인
docker exec -it myk8s-control-plane istioctl proxy-config secret $ISTIOIGW
docker exec -it myk8s-control-plane istioctl proxy-config secret $WEBAPP

위 명령어들은 istio 서비스 매쉬 내 프록시의 상태를 확인(istioctl proxy-status)하고, 특정 프록시의 상세 구성 정보를 조회(istioctl proxy-config)하는 명령어다.

Istio 프록시(Envoy)의 네트워크 흐름에서 Listener, Route, Cluster, Endpoint는 트래픽 처리 단계에 따라 아래와 같은 순서로 작동합니다:

1. Listener
역할: Envoy가 수신하는 트래픽을 처리할 준비를 합니다. Listener는 특정 IP와 포트에 바인딩되어 들어오는 요청을 수신하고, 트래픽을 처리하기 위한 첫 번째 진입점입니다.

작동 위치: 네트워크에서 Envoy 프록시가 요청을 가로채고, 트래픽의 방향을 결정하기 위해 필터 체인을 적용합니다.

예시: HTTP 요청이 들어오면 Listener는 이를 처리할 라우팅 규칙을 찾습니다.

2. Route
역할: Listener에서 수신된 요청을 분석하여 어떤 서비스로 전달할지 결정합니다. Route는 요청 경로와 매칭되는 규칙을 기반으로 클러스터를 선택합니다.

작동 위치: Listener에서 필터 체인을 통해 전달된 요청은 Route에서 적절한 클러스터로 연결됩니다.

예시: 특정 URL 경로(/api/v1)에 대한 요청을 특정 클러스터로 라우팅.

3. Cluster
역할: 라우팅된 요청을 처리할 논리적인 서비스 그룹입니다. Cluster는 여러 Endpoint(IP와 포트)로 구성되며, Envoy가 외부 서비스와 연결하는 단위입니다.

작동 위치: Route가 선택한 클러스터는 실제 엔드포인트로 트래픽을 포워드합니다.

예시: service-cluster라는 클러스터가 외부 API 서버를 대표하며, 해당 클러스터의 엔드포인트로 트래픽을 전달.

4. Endpoint
역할: 클러스터 내에서 실제 요청이 전달되는 대상입니다. Endpoint는 IP 주소와 포트를 포함하며, 클라이언트의 요청이 최종적으로 도달하는 곳입니다.

작동 위치: Cluster에서 선택된 엔드포인트로 트래픽이 전달됩니다.

예시: 특정 API 서버의 IP 주소(예: 192.168.1.100)와 포트(예: 8080)이 Endpoint로 설정됩니다.

네트워크 흐름 순서 요약
단계    구성 요소    역할 및 작업
1    Listener    요청 수신 및 필터 체인을 통해 초기 처리
2    Route    요청 경로 분석 및 적절한 클러스터 선택
3    Cluster    논리적 서비스 그룹으로 요청 전달
4    Endpoint    실제 대상(IP/포트)으로 최종 트래픽 전달
이 순서는 Istio 프록시의 기본적인 트래픽 처리 흐름이며, 각 단계는 Envoy 내부의 설정과 xDS API를 통해 동적으로 구성됩니다.

의도적으로 ingress, gateway, VirtualService 설정중 한곳에 문제를 주고 해당 서비스가 어떤 문제가 있는지 한번 위 명령어들로 확인해보고자 한다.

먼저 문제있는 서비스의 Ingress와 gateway, Virtual Service 설정은 다음과 같이 진행했다.

$ k get ingress -n istio-system | grep query
query-ingress   alb     query.test.com                                                        query-server-ingress-fin.lb.naverncp.com    80      107d

위와같이 query-ingress는 현재 NCP ALB로 연결 된 상태다.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
중략
  labels:
    app: query-server-ingress
  name: query-server-ingress
  namespace: istio-system
spec:
  ingressClassName: alb
  defaultBackend:
    service:
      name: istio-ingressgateway
      port:
        number: 80
  rules:
  - host: query-test.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: ssl-redirect
            port: 
              name: use-annotation            

GW와 VS 매니페스트는 다음과 같다.

apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
중략
  creationTimestamp: "2024-12-13T01:46:08Z"
  generation: 1
  labels:
    app.kubernetes.io/instance: opsquery
  name: query-gateway
  namespace: istio-system
  resourceVersion: "441696723"
  uid: 19fc1bd0-5c30-4dc1-b624-b956da859c15
spec:
  selector:
    istio: ingressgateway
  servers:
  - hosts:
    - query.test.co.kr
    port:
      name: http
      number: 80
      protocol: HTTP


---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ops-query-vs
  namespace: devops
spec:
  hosts:
  - "ops-query.test.co.kr"
  gateways:
  - istio-system/devops-gateway
  http:
  - match:
    - uri:
        prefix: /
    route:
    - destination:
        host: query-svc-active
      weight: 100
    - destination:
        host: query-svc-preview
      weight: 0

이제 proxy-status와 proxy-config 명령어로 한번 원인을 찾아보고자 한다.

$ istioctl proxy-status | grep ops-query
ops-query-7cc7fc6f69-b6sml.devops                                    Kubernetes     SYNCED     SYNCED     SYNCED     SYNCED     NOT SENT     istiod-784bcfdd5d-2fgbs     1.16.2

$ istioctl proxy-config all ops-query-7cc7fc6f69-b6sml.devops | grep ops 
##결과 없음

결과가 없다는건 Gateway나 VirtualService에 문제가 있을 가능성이 크다(고한다.)

Gateway 설정 문제:
Gateway가 Istio IngressGateway Pod와 제대로 연결되지 않았을 수 있습니다.
Gateway의 selector가 IngressGateway Pod의 라벨과 일치하지 않으면 트래픽을 수신할 Listener가 생성되지 않습니다.

VirtualService 설정 누락 또는 연결 문제:
VirtualService가 Gateway와 연계되어 있지 않거나, VirtualService에서 트래픽 라우팅 규칙이 제대로 정의되지 않았을 경우 Listener가 생성되지 않습니다.
VirtualService가 없으면 Gateway는 트래픽 처리 규칙을 알 수 없어 Listener를 생성하지 않습니다.

Istiod 구성 전달 문제:
Istiod(Control Plane)에서 Envoy 프록시(데이터 플레인)로 Gateway 및 VirtualService 설정이 전달되지 않았을 가능성이 있습니다.
이는 Istiod와 IngressGateway 간의 통신 문제, 혹은 설정 동기화 실패(STALE 상태)가 원인일 수 있습니다.

그럼 Ingress, GW, VS설정에 문제가 없는지 찾아보면 될것이다. 사실 VS 설정중 게이트웨이 설정하는부분을 잘못 넣어놨었다.

gateways:
-   istio-system/devops-gateway

정상적으로 하려면 devops-gateway가 아니라 query-gateway 으로 설정해줘야 한다.

$ istioctl proxy-config all ops-query-7cc7fc6f69-b6sml.devops  | grep ops-query
ops-query-svc-active.devops.svc.cluster.local                                  80        -          outbound      EDS              
ops-query-svc-preview.devops.svc.cluster.local                                 80        -          outbound      EDS              
80                                                                                   ops-query-svc-active, ops-query-svc-active.devops + 1 more...                                                            /*                     
80                                                                                   ops-query-svc-preview, ops-query-svc-preview.devops + 1 more...                                                          /*     

서비스도 정상적으로 동작하고, proxy-config 의 결과에도 정상적으로 출력되는것이 확인된다.
proxy-config에 대한(리스너, 라우드, 클러스터, 엔드포인트등 xDS)자세한 설명은 다음 주차때 envoy프록시 설명에서 자세히 다룰듯 하다.

다시 실습으로 넘어가서...

# istio-ingressgateway 서비스 NodePort 변경 및 nodeport 30000로 지정 변경
kubectl get svc,ep -n istio-system istio-ingressgateway
kubectl patch svc -n istio-system istio-ingressgateway -p '{"spec": {"type": "NodePort", "ports": [{"port": 80, "targetPort": 8080, "nodePort": 30000}]}}'
kubectl get svc -n istio-system istio-ingressgateway

# istio-ingressgateway 서비스 externalTrafficPolicy 설정 : ClientIP 수집 확인
kubectl patch svc -n istio-system istio-ingressgateway -p '{"spec":{"externalTrafficPolicy": "Local"}}'
kubectl describe svc -n istio-system istio-ingressgateway

curl -s http://127.0.0.1:30000/api/catalog | jq
curl -s http://127.0.0.1:30000/api/catalog/items/1 | jq
curl -s http://127.0.0.1:30000/api/catalog -I | head -n 1

위 명령어들로 실습환경의 30000포트로 접속가능하도록 설정해주고 curl로 접속을 확인하면 다음과 같이 정상적으로 접속됨을 확인 할 수 있다.

옵저버빌리티

이제 옵저버빌리티를 하기 위해 추가 설치한 프로메테우스, 그라파나, 키알리, 트레이싱에 대한 노드포트를 설정해준다.

kubectl patch svc -n istio-system prometheus -p '{"spec": {"type": "NodePort", "ports": [{"port": 9090, "targetPort": 9090, "nodePort": 30001}]}}'
kubectl patch svc -n istio-system grafana -p '{"spec": {"type": "NodePort", "ports": [{"port": 3000, "targetPort": 3000, "nodePort": 30002}]}}'
kubectl patch svc -n istio-system kiali -p '{"spec": {"type": "NodePort", "ports": [{"port": 20001, "targetPort": 20001, "nodePort": 30003}]}}'
kubectl patch svc -n istio-system tracing -p '{"spec": {"type": "NodePort", "ports": [{"port": 80, "targetPort": 16686, "nodePort": 30004}]}}'

이후 localhost:서비스포트 로 접속하면 정상적으로 접속됨을 확인할 수 있다. 이중 Kiali를 살펴보면..

 

이미지와 같이 서비스매쉬의 트래픽 흐름을 확인 할 수 있다. 아까 장애 상황에서 라면 istio-ingressgateway에서 webapp으로 흐르는 트래픽이 안나왔을것이다.

 

이제 해당 서비스에 강제로 500에러를 50프로 빈도로 발생하도록 하면 kiali에서 다음 화면 처럼 실패가 나고 있는것을 볼 수 있다.

 

실무환경에서도 여러가지 이유로 간헐적으로 5xx대 에러가 발생할 수 있는데, 이때 다음 설정으로 5xx에러 발생시 재시도를 하도록 조치 할 수 있다.

cat <<EOF | kubectl -n istioinaction apply -f -
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: catalog
spec:
  hosts:
  - catalog
  http:
  - route:
    - destination:
        host: catalog
    retries:
      attempts: 3
      retryOn: 5xx
      perTryTimeout: 2s
EOF

 

위 설정은 만약 5xx대 에러 발생시 2초 뒤 3번 재시도 하도록 할 수 있다. 사이드카 방식 istio의 큰 장점이라고 본다.

 

이밖에, istio 만으로 트래픽을 컨트롤하여 여러가지 배포방법을 이용할 수 있다.

 

우리는 argocd를 사용중인데, VS에서 route 설정으로 weight으로 active, preview를 설정하여 블루/그린 배포방법을 이용중이다.

 

추가로 다음과같이 VS에 헤더를 기반으로 매칭을 확인하여 트래픽을 보낼 수 있다.

cat <<EOF | kubectl -n istioinaction apply -f -
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: catalog
spec:
  hosts:
  - catalog
  http:
  - match:
    - headers:
        x-dark-launch:
          exact: "v2"
    route:
    - destination:
        host: catalog
        subset: version-v2
  - route:
    - destination:
        host: catalog
        subset: version-v1
EOF

 

현재 운영환경에서 아르고 롤아웃으로 프리뷰가 배포 됐을 때, promote 하기 전에 해당 배포버전으로 미리 접속하여 QA를 진행하고자 할 수 있다. 이때 굉장히 유용할듯 하다.

 

마지막으로...

istio를 사용하면서 istio 컨테이너의 로그를 자세히 봐야 할 필요가 있었다.

실사례로, 프론트에서는 아무런 값이 안들어왔고, 백앤드에서는 데이터를 정상적으로 전송했다고 한다. 이때 istio 컨테이너 로그를 확인 할 필요가 있었다. 왜냐하면 결국 데이터가 전송됐다면 istio 로그에 찍혔을테니까 말이다. 

 

그래서 다음과같은 설정을 적용해서 로그를 찍었다.

 

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: request-size-limit
  namespace: test
spec:
  workloadSelector:
    labels:
      app: test-api
  configPatches:
  - applyTo: HTTP_FILTER
    match:
      context: ANY
      listener:
        filterChain:
          filter:
            name: envoy.filters.network.http_connection_manager
            subFilter:
              name: envoy.filters.http.router
    patch:
      operation: INSERT_BEFORE
      value:
        name: envoy.filters.http.buffer
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.http.buffer.v3.Buffer
          max_request_bytes: 50485760


  - applyTo: HTTP_FILTER
    match:
      context: ANY
      listener:
        filterChain:
          filter:
            name: envoy.filters.network.http_connection_manager
            subFilter:
              name: envoy.filters.http.router
    patch:
      operation: INSERT_BEFORE
      value:
        name: envoy.filters.http.lua
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua
          inlineCode: |
            function envoy_on_response(response_handle)
              local headers = response_handle:headers()
              for key, value in pairs(headers) do
                response_handle:logInfo("response Header:" .. key .. ":"  .. value)
              end
              local response_body = response_handle:body():getBytes(0,response_handle:body():length())
              response_handle:logInfo("response body:" .. response_body)
            end

  - applyTo: LISTENER
    match:
      context: ANY
    patch:
      operation: MERGE
      value:
        per_connection_buffer_limit_bytes: 20480000

 

해당 설정은 요청에 대한 response body 용량과 실제 body 내용을 로그로 남기는 설정이다.

 

마무리..

1주차부터 좋은 지식을 많이 얻었다. 스터디 운영진님들 감사합니다.

'job > devops' 카테고리의 다른 글

istio-2  (1) 2025.04.17
taskfile  (0) 2024.03.10
kubewarden  (0) 2024.01.20
openfunction  (0) 2023.12.01
git common flow(또는 gitlab flow) 브랜치 전략에 대한 설명  (0) 2023.06.13

1. 패키지 관리 도구 및 저장소별로 nexus 프록시 타입 레포 생성

2. maven, npm등 포맷별로 만들어진 proxy 레포를 하나의 그룹으로 묶기

3. 깃헙에서 소스 패키지를 태그나 릴리즈등으로 받는 경우는 raw host 만들어서 직접 파일 업로드하여 패키지 관리. 물론 raw host들도 그룹으로 묶기

4. 빌드 환경에 따라 기존 디폴트 퍼블릭 저장소를 넥서스 그룹 저장소로 변경하기

5. 패키지 설치 후 빌드하는 과정에서 디펜던시 패키지가 또다시 패키지를 설치하는경우가 있음. 따라서 패키지 설치후 디펜던시 패키지내에 추가적으로 기존 디폴트 퍼블릭 저장소를 넥서스 그룹 저장소로 변경해야 할 수 있음

큰 틀로 보면 위 순서대로 하면 된다. 

 

구축된 환경들을 나열해보면

React Native, Flutter, Yarn, Maven, NPM, Docker image, composer, python, cocoapod, rubygem

그리고 apk, yum, homebrew, nuget까지.. 많이 사용되는 대부분의 환경은 다 한 것 같다.

 

해당 업무를 하면서 조언을 얻기가 쉽지 않았다.  우리나라에 망분리 환경에서 개발하는 개발자들이 그렇게 많겠지만 개발자는 인프라영역을 모르고, 인프라담당자는 개발영역을 잘 몰르니 말이다. 그래서 난관이 좀 많았다. 망분리 개발환경 구축만큼은 나름 목소리좀 낼 수 있을듯 하다.

어쨌든 뭐. 이정도면 나름 만족스러운 결과(개발자도 최대한 불편하지 않고, 보안에도 위법되지 않고)인듯 하다.

 

마지막으로 각 단계에서 발생했던 난관들을 적어보자면...

1. 패키지 관리 도구 및 저장소별로 nexus 프록시 타입 레포 생성

넥서스 캐시등의 설정에 유의해야하고.

넥서스에서 기본적으로 제공하는 레시피가 제한적이다. 그럴땐 넥서스 레포 '패키지관리도구이름' 검색해보면 직접 레시피 만들 수 있도록 깃헙에 등록돼있는 경우가 있음.(ex apk)

 

2. maven, npm등 포맷별로 만들어진 proxy 레포를 하나의 그룹으로 묶기

이건 뭐 어려울껀 없다.. 가장 많이 사용하는 레포를 순서상 가장 위로 하도록

 

3. 깃헙에서 소스 패키지를 태그나 릴리즈등으로 받는 경우는 raw host 만들어서 직접 파일 업로드하여 패키지 관리. 물론 raw host들도 그룹으로 묶기

Nexus는 기본적으로 바이너리 컴포넌트 관리 솔루션으로 설계되었으며, 소스 코드 관리 시스템이 아니다. 따라서 GitHub과 같은 소스 코드 저장소를 직접적으로 프록시하거나 통합하는 데 적합하지 않다.

그래서 패키지를 깃헙에서 받는 경우에는 어떻게 해야할까 고민이 많았다. 기 구축된 내부 깃랩 서버가 있어서 처음엔 깃헙>깃랩을 동일하게 구성(미러링 되도록)해서 해결해볼까 했다.

그러나 이경우 깃헙에서 기본적으로 사용하는 태그/아카이브/릴리즈 경로와 깃랩의 경로가 서로 달랐다. 미러링하다보니까 모든 패키지를 다 다운받아야하니 불필요하게 깃랩의 용량이 커지는것도 싫었다.

그래서 결국 필요한 패키지를 깃헙에서 다운받아 raw host 넥서스 레포로 업로드 하도록 했다. 현재 내가 다니는 회사의 규모가 크진 않아서 필요한 패키지를 직접 수동으로 업로드하긴 했는데, 만약 자동화가 필요하다면 구글 시트에 개발자가 필요한 패키지이름/깃헙 경로 업로드하면 스케쥴링 걸어서 자동으로 넥서스 레포에 업로드 하도록 하면 될듯 싶다.

 

4. 빌드 환경에 따라 기존 디폴트 퍼블릭 저장소를 넥서스 그룹 저장소로 변경하기

CI/CD 자동화 환경에서는 dockerfile에서 직접 설정을 해야 하고, 개발자 개인 개발 PC에서의 설정은 개발자가 해야 할 일이다.

패키지 저장소별 설정 방법 가이드는 https://help.sonatype.com/en/formats.html 를 참고하면 된다.

 

5. 패키지 설치 후 빌드하는 과정에서 디펜던시 패키지가 또다시 패키지를 설치하는경우가 있음. 따라서 패키지 설치후 디펜던시 패키지내에

추가적으로 기존 디폴트 퍼블릭 저장소를 넥서스 그룹 저장소로 변경해야 할 수 있음

앞서 깃헙과 함께 가장 골치 아픈 상황이였다. 특히 프론트개발환경에 React Native에서 많았다. 이건 뭐.. 어쩔 수 없다. 이것도 찾아서 다 바꿔야 한다. 빌드 도구별로 패치 기능이 또 있어서 잘 활용하면 된다.

패키지 설치 -> 패치 -> 빌드 가 가능한 환경이면 devops가 replace(기존 저장소를 내부 넥서스로)를 할 수 있다. 근데 애매한게... 빌드 하는 과정에서 패치가 필요한경우가 있다. 이때는 개발자가 소스코드에서 직접 수정해줬다. 예를들어 Gradle 같은 경우는 init.gradle에서 설정이 가능하다.

 

 

넥서스에서 제공하는 기본 repository recipe중에 apk는 없다.

 

ps.

나는 apt랑 헷갈려서 apt로 만들었다가 다음과 같은 에러를 만났다.

package mentioned in index not found (try 'apk update')

 

어쨋든 apk용 레포를 만들기 위해 넥서스에 apk recipe를 추가해보자.

 

1. git clone https://github.com/sonatype-nexus-community/nexus-repository-apk.git

2. cd nexus-repo tab

3. mvn clean package -PbuildKar

3-1. mvn 없으면 maven 설치

3-2. 빌드가 완료되면 target 폴더에 .kar 파일이 생성됩니다

4. 생성된 .kar 파일을 Nexus Repository의 deploy 폴더로 복사

5. 넥서스 재시작

1

 

'job > linux' 카테고리의 다른 글

기본 엔지니어링 체크리스트  (0) 2024.03.20
docker Exited (137)  (0) 2024.01.09
ci/cd 파이프라인  (0) 2022.11.16
간헐적 500 Server Internal Error 원인 파악하기  (0) 2022.11.10
du -sch --exclude  (0) 2022.07.11

집합 자료형은 중복되지 않는 고유한 요소들의 모음을 저장하는 자료형으로, 여러 가지 실무 상황에서 유용하게 사용할 수 있다. 집합은 중괄호 {}를 사용하여 생성하며, 다양한 집합 연산을 지원한다. 아래에서는 집합 자료형을 실무에서 사용할 수 있는 몇 가지 상황을 설명해보겠다.

1. 중복 제거

가장 일반적인 집합의 사용 사례는 중복된 데이터를 제거하는 것이다. 예를 들어, 고객 이메일 목록에서 중복된 이메일 주소를 제거할 때 유용하다.

예시

emails = ["alice@example.com", "bob@example.com", "alice@example.com", "charlie@example.com"]
unique_emails = set(emails)
print(unique_emails)  # 출력: {'alice@example.com', 'bob@example.com', 'charlie@example.com'}

2. 교집합, 합집합, 차집합 연산

집합은 교집합, 합집합, 차집합 등의 집합 연산을 효율적으로 수행할 수 있다. 이는 데이터 분석, 필터링 등에 매우 유용하다.

예시

# 두 집합 생성
set_a = {"apple", "banana", "cherry"}
set_b = {"banana", "cherry", "date", "fig"}

# 교집합
intersection = set_a & set_b
print(intersection)  # 출력: {'banana', 'cherry'}

# 합집합
union = set_a | set_b
print(union)  # 출력: {'apple', 'banana', 'cherry', 'date', 'fig'}

# 차집합
difference = set_a - set_b
print(difference)  # 출력: {'apple'}

3. 데이터 무결성 유지

집합은 중복을 허용하지 않기 때문에, 데이터 무결성을 유지하는 데 유용하다. 예를 들어, 사용자 ID나 제품 코드와 같이 고유해야 하는 데이터를 저장할 때 사용한다.

예시

user_ids = {"user1", "user2", "user3"}

# 새로운 사용자 ID 추가
user_ids.add("user4")
print(user_ids)  # 출력: {'user1', 'user2', 'user3', 'user4'}

# 중복된 사용자 ID 추가 시도
user_ids.add("user2")
print(user_ids)  # 출력: {'user1', 'user2', 'user3', 'user4'} (중복 추가되지 않음)

4. 빠른 멤버십 테스트

집합은 특정 요소가 집합에 존재하는지 빠르게 확인할 수 있다. 이는 대규모 데이터에서 특정 요소를 검색할 때 유용하다.

예시

# 대규모 데이터 집합 생성
large_set = set(range(1000000))

# 특정 요소 존재 여부 확인
print(999999 in large_set)  # 출력: True
print(1000000 in large_set)  # 출력: False

5. 태그 시스템

집합은 태그 시스템을 구현할 때 유용하다. 예를 들어, 블로그 게시물에 여러 태그를 추가하고, 특정 태그를 가진 게시물을 검색할 때 사용한다.

예시

# 게시물에 태그 추가
post_tags = {"python", "programming", "tutorial"}

# 새로운 태그 추가
post_tags.add("coding")
print(post_tags)  # 출력: {'python', 'programming', 'tutorial', 'coding'}

# 특정 태그 존재 여부 확인
print("python" in post_tags)  # 출력: True
print("java" in post_tags)    # 출력: False

결론

집합 자료형은 중복 제거, 집합 연산, 데이터 무결성 유지, 빠른 멤버십 테스트, 태그 시스템 등 다양한 실무 상황에서 유용하게 사용할 수 있다. 집합의 특성과 장점을 이해하고 적절히 활용하면 데이터 처리와 분석을 더욱 효율적으로 수행할 수 있다.

프로그래밍을 할 때 리스트와 튜플을 사용하여 데이터를 저장할 수 있다. 이 두 자료형은 많은 면에서 비슷하지만, 메모리 사용량에서는 차이가 있다. 이 글에서는 리스트와 튜플의 메모리 사용량 차이를 설명해보겠다.

리스트와 튜플의 메모리 사용량 비교

리스트와 튜플은 각각 데이터를 저장하는 방식이 다르기 때문에 메모리 사용량에서도 차이가 난다. 일반적으로 튜플이 리스트보다 메모리를 덜 사용한다.

예시

# 리스트와 튜플 생성
a_list = [1, 2, 3]
a_tuple = (1, 2, 3)

# 메모리 사용량 확인
print(a_list.__sizeof__())  # 출력: 64
print(a_tuple.__sizeof__())  # 출력: 48

위 예시에서 볼 수 있듯이, 동일한 데이터를 저장할 때 리스트는 64바이트를 사용하고, 튜플은 48바이트를 사용한다.

메모리 사용량 차이의 이유

  1. 가변성:
    • 리스트는 가변적이어서 요소를 추가하거나 삭제할 수 있다. 이를 위해 리스트는 추가적인 메모리를 할당하여 데이터를 저장하고 관리해야 한다. 반면, 튜플은 불변적이어서 한 번 생성되면 변경할 수 없다. 따라서 튜플은 고정된 메모리만 할당하면 된다.
  2. 오버 할당:
    • 리스트는 요소를 추가할 때마다 메모리를 재할당하는 비용을 줄이기 위해 오버 할당(over-allocation) 기법을 사용한다. 이는 리스트가 더 많은 메모리를 사용할 수 있게 한다. 반면, 튜플은 이러한 오버 할당이 필요 없으므로 더 적은 메모리를 사용한다[1][2].
  3. 구조적 차이:
    • 리스트는 각 요소에 대한 포인터를 저장하는 데 추가 메모리를 사용한다. 반면, 튜플은 이러한 포인터를 저장하지 않아 더 적은 메모리를 사용한다[1].

[1] https://stackoverflow.com/questions/46664007/why-do-tuples-take-less-space-in-memory-than-lists

[2] https://www.reddit.com/r/learnpython/comments/1b9rdxq/list_vs_tuple_mutable_vs_immutable_performance/

Citations: [1] https://stackoverflow.com/questions/46664007/why-do-tuples-take-less-space-in-memory-than-lists [2] https://www.reddit.com/r/learnpython/comments/1b9rdxq/list_vs_tuple_mutable_vs_immutable_performance/ [3] https://stackoverflow.com/questions/20771470/list-memory-usage [4] https://www.geeksforgeeks.org/memory-management-in-lists-and-tuples-using-python/ [5] https://www.geeksforgeeks.org/python-memory-consumption-dictionary-vs-list-of-tuples/ [6] https://www.upgrad.com/blog/list-vs-tuple/ [7] https://github.com/BecomeWeasel/daily_algo_challenge/issues/2

프로그래밍을 할 때 리스트와 튜플을 언제 사용해야 할지 고민될 수 있다. 리스트와 튜플은 모두 데이터를 순서대로 저장할 수 있는 자료형이지만, 몇 가지 중요한 차이점이 있다.

리스트 (List)

리스트는 데이터를 수정, 추가, 삭제할 수 있는 변경 가능한 자료형이다. 대괄호 []로 감싸서 만들며, 다양한 데이터를 저장할 수 있다. 리스트는 다음과 같은 상황에서 사용하기 좋다:

  1. 데이터가 자주 변경될 때:
    • 리스트는 데이터를 자유롭게 수정할 수 있다. 예를 들어, 쇼핑 목록이나 할 일 목록처럼 자주 업데이트해야 하는 데이터를 저장할 때 유용하다.
  2. 동적 크기 조정이 필요할 때:
    • 리스트는 크기를 동적으로 조정할 수 있다. 데이터를 추가하거나 삭제할 수 있어, 크기가 변동하는 데이터에 적합하다.

튜플 (Tuple)

튜플은 한 번 생성되면 수정할 수 없는 변경 불가능한 자료형이다. 소괄호 ()로 감싸서 만들며, 다양한 데이터를 저장할 수 있다. 튜플은 다음과 같은 상황에서 사용하기 좋다:

  1. 데이터가 변경되지 않을 때:
    • 튜플은 데이터가 변경되지 않아야 할 때 사용하기 좋다. 예를 들어, 좌표나 RGB 색상 값처럼 고정된 데이터를 저장할 때 유용하다.
  2. 데이터의 무결성을 유지해야 할 때:
    • 튜플은 변경할 수 없기 때문에 데이터의 무결성을 유지할 수 있다. 중요한 데이터를 보호할 때 적합하다.
  3. 메모리 사용을 최적화할 때:
    • 튜플은 리스트보다 메모리를 적게 사용하고, 처리 속도가 빠르다. 따라서 메모리 사용을 최적화해야 하는 상황에서 유용하다.

리스트와 튜플의 차이점 정리

특징 리스트 (List) 튜플 (Tuple)

생성 방법 대괄호 [] 사용 소괄호 () 사용
변경 가능 여부 변경 가능 (요소 수정, 추가, 삭제 가능) 변경 불가능 (요소 수정, 추가, 삭제 불가)
사용 예시 동적으로 변하는 데이터 관리에 유용하다 고정된 데이터 관리에 유용하다

결론

리스트와 튜플은 각각의 특성과 장점을 가지고 있다. 리스트는 데이터가 자주 변경되거나 크기가 변동할 때 사용하기 좋다. 반면, 튜플은 데이터가 변경되지 않아야 하거나 데이터의 무결성을 유지해야 할 때, 그리고 메모리 사용을 최적화해야 할 때 사용하기 좋다.

리스트 (List)

리스트는 여러 데이터를 순서대로 저장할 수 있는 자료형이다. 리스트는 대괄호 []로 감싸서 만들고, 각 요소는 쉼표 ,로 구분한다. 리스트의 가장 큰 특징은 변경 가능하다는 점이다. 즉, 리스트에 있는 데이터를 수정, 추가, 삭제할 수 있다.

예시

# 리스트 생성
fruits = ["사과", "바나나", "딸기"]

# 리스트 요소 변경
fruits[1] = "오렌지"  # 바나나를 오렌지로 변경
print(fruits)  # 출력: ['사과', '오렌지', '딸기']

# 리스트에 요소 추가
fruits.append("포도")
print(fruits)  # 출력: ['사과', '오렌지', '딸기', '포도']

# 리스트에서 요소 삭제
fruits.remove("딸기")
print(fruits)  # 출력: ['사과', '오렌지', '포도']

튜플 (Tuple)

튜플은 리스트와 비슷하게 여러 데이터를 순서대로 저장할 수 있는 자료형이다. 하지만 튜플은 소괄호 ()로 감싸서 만들고, 리스트와 달리 변경 불가능하다. 즉, 한 번 생성된 튜플의 요소는 수정, 추가, 삭제할 수 없다.

예시

# 튜플 생성
colors = ("빨강", "초록", "파랑")

# 튜플 요소 접근
print(colors[1])  # 출력: 초록

# 튜플 요소 변경 시도 (오류 발생)
# colors[1] = "노랑"  # 오류: 튜플은 변경할 수 없음

# 튜플에 요소 추가 시도 (오류 발생)
# colors.append("노랑")  # 오류: 튜플은 변경할 수 없음

리스트와 튜플의 차이점 정리

특징 리스트 (List) 튜플 (Tuple)

생성 방법 대괄호 [] 사용 소괄호 () 사용
변경 가능 여부 변경 가능 (요소 수정, 추가, 삭제 가능) 변경 불가능 (요소 수정, 추가, 삭제 불가)
사용 예시 동적으로 변하는 데이터 관리에 유용하다 고정된 데이터 관리에 유용하다

결론

리스트와 튜플은 여러 데이터를 관리할 때 매우 유용한 자료형이다. 리스트는 데이터를 자유롭게 수정, 추가, 삭제할 수 있어 유연성이 높다. 반면, 튜플은 한 번 생성되면 변경할 수 없기 때문에 데이터의 무결성을 유지하는 데 유리하다. 이 두 자료형의 차이를 이해하고 상황에 맞게 사용하는 것이 중요하다.

2차원 배열이란

2차원 배열은 숫자나 문자를 정리해서 저장할 수 있는 표와 같은 것이다. 엑셀이나 구글 스프레드시트를 생각해보면 쉽게 이해할 수 있다. 표의 각 칸에는 하나의 값이 들어가고, 이 값들은 행과 열로 구분된다.

2차원 배열의 예시

예를 들어, 다음과 같은 표가 있다고 하자:

0열 1열 2열

0행 1 2 3
1행 4 5 6
2행 7 8 9

이 표는 3개의 행과 3개의 열로 이루어져 있다. 각 칸에는 숫자가 들어있다. 이 표를 2차원 배열이라고 부른다.

파이썬에서 2차원 배열 만들기

파이썬에서는 리스트라는 것을 사용해서 2차원 배열을 만들 수 있다. 리스트는 여러 개의 값을 한 곳에 모아놓는 방법이다. 2차원 배열을 만들기 위해서는 리스트 안에 리스트를 넣으면 된다.

array = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]

위의 코드는 3x3 크기의 2차원 배열을 만든다. 첫 번째 리스트 [1, 2, 3]는 첫 번째 행을 나타내고, 두 번째 리스트 [4, 5, 6]는 두 번째 행을 나타낸다.

2차원 배열에서 값 꺼내기

2차원 배열에서 특정 값을 꺼내려면 행과 열의 위치를 알려줘야 한다. 예를 들어, 첫 번째 행과 두 번째 열에 있는 값을 꺼내려면 다음과 같이 하면 된다.

value = array[0][1]  # 결과는 2

여기서 array은 첫 번째 행(0행)과 두 번째 열(1열)에 있는 값을 의미한다. 파이썬에서는 숫자를 셀 때 0부터 시작한다는 점을 기억하자.

2차원 배열에서 부분 배열 꺼내기

2차원 배열에서 여러 개의 값을 한꺼번에 꺼내는 것도 가능하다. 이를 슬라이싱이라고 한다. 예를 들어, 첫 번째와 두 번째 행을 꺼내려면 다음과 같이 한다.

rows = array[0:2]  # 결과는 [[1, 2, 3], [4, 5, 6]]

여기서 array[0:2]는 첫 번째 행(0행)과 두 번째 행(1행)을 의미한다.

2차원 배열에서 인덱싱과 슬라이싱을 활용하면 특정 행, 열 또는 부분 배열을 쉽게 추출할 수 있다. 이를 통해 데이터 분석, 이미지 처리 등 다양한 분야에서 효율적으로 데이터를 다룰 수 있다. 아래 예제는 NumPy 라이브러리를 사용하여 2차원 배열을 처리하는 방법을 보여준다.

예시: 2차원 배열 생성 및 인덱싱, 슬라이싱

먼저, NumPy를 사용하여 2차원 배열을 생성하고, 인덱싱과 슬라이싱을 통해 특정 부분을 추출하는 예제를 살펴보자.

import numpy as np

# 2차원 배열 생성
array = np.array([
    [1, 2, 3, 4, 5],
    [6, 7, 8, 9, 10],
    [11, 12, 13, 14, 15],
    [16, 17, 18, 19, 20]
])

# 배열 출력
print("원본 배열:")
print(array)

인덱싱 예제

특정 행과 열의 요소를 추출하는 방법이다.

# 두 번째 행의 세 번째 요소 (8) 추출
element = array[1, 2]
print("\\\\n두 번째 행의 세 번째 요소:", element)

# 마지막 행의 마지막 요소 (20) 추출
element = array[-1, -1]
print("마지막 행의 마지막 요소:", element)

슬라이싱 예제

배열의 특정 부분을 추출하는 방법이다.

# 첫 두 행과 첫 세 열 추출
sub_array = array[:2, :3]
print("\\\\n첫 두 행과 첫 세 열:")
print(sub_array)

# 두 번째 행부터 끝까지, 세 번째 열부터 네 번째 열까지 추출
sub_array = array[1:, 2:4]
print("\\\\n두 번째 행부터 끝까지, 세 번째 열부터 네 번째 열까지:")
print(sub_array)

# 모든 행에서 두 번째 열만 추출
column = array[:, 1]
print("\\\\n모든 행에서 두 번째 열:")
print(column)

# 모든 열에서 세 번째 행만 추출
row = array[2, :]
print("\\\\n모든 열에서 세 번째 행:")
print(row)

문자열 인덱싱

문자열 인덱싱은 문자열의 특정 위치에 있는 문자를 가져오는 방법이다. 인덱스는 0부터 시작하며, 음수 인덱스를 사용하면 문자열의 끝에서부터 역순으로 접근할 수 있다.

# 문자열 설정
text = "Hello, World!"

# 인덱싱 예제
print(text[0])  # 출력: H (첫 번째 문자)
print(text[7])  # 출력: W (여덟 번째 문자)
print(text[-1])  # 출력: ! (마지막 문자)
print(text[-5])  # 출력: o (뒤에서 다섯 번째 문자)

문자열 슬라이싱

문자열 슬라이싱은 문자열의 일부분을 추출하는 방법이다. 슬라이싱은 [start:end:step] 형식을 사용하며, start는 시작 인덱스, end는 끝 인덱스(포함되지 않음), step은 간격을 의미한다.

# 문자열 설정
text = "Hello, World!"

# 슬라이싱 예제
print(text[0:5])  # 출력: Hello (0번 인덱스부터 4번 인덱스까지)
print(text[7:12])  # 출력: World (7번 인덱스부터 11번 인덱스까지)
print(text[:5])  # 출력: Hello (처음부터 4번 인덱스까지)
print(text[7:])  # 출력: World! (7번 인덱스부터 끝까지)
print(text[:])  # 출력: Hello, World! (전체 문자열)
print(text[::2])  # 출력: Hlo ol! (2칸씩 건너뛰며 추출)
print(text[::-1])  # 출력: !dlroW ,olleH (역순으로 추출)

인덱싱과 슬라이싱을 동시에 활용한 실무 예제 - 로그 파일에서 날짜와 오류 메시지 추출하기

문자열 인덱싱과 슬라이싱을 동시에 활용하면 문자열의 특정 부분을 효율적으로 추출하고 조작할 수 있다. 예를 들어, 로그 파일에서 특정 정보를 추출하거나, 텍스트 데이터에서 특정 패턴을 찾는 작업에 유용하다.

로그 파일의 각 줄에서 날짜와 오류 메시지를 추출하는 예제를 살펴보자. 로그 파일의 형식은 다음과 같다:

2024-08-07 12:34:56 ERROR: Something went wrong
2024-08-07 12:35:56 INFO: All systems operational
2024-08-07 12:36:56 ERROR: Another error occurred

이 로그 파일에서 날짜와 오류 메시지만 추출하는 코드를 작성해보자.

# 로그 파일의 각 줄을 리스트로 저장
log_lines = [
    "2024-08-07 12:34:56 ERROR: Something went wrong",
    "2024-08-07 12:35:56 INFO: All systems operational",
    "2024-08-07 12:36:56 ERROR: Another error occurred"
]

# 날짜와 오류 메시지를 추출하는 함수
def extract_error_info(log_lines):
    for line in log_lines:
        if "ERROR" in line:
            # 날짜 추출 (인덱싱과 슬라이싱을 동시에 활용)
            date = line[:10]  # 처음 10글자: 2024-08-07
            # 오류 메시지 추출
            error_message = line[line.index("ERROR:") + 7:]  # "ERROR:" 다음부터 끝까지
            print(f"Date: {date}, Error: {error_message}")

# 함수 호출
extract_error_info(log_lines)

결과

Date: 2024-08-07, Error: Something went wrong
Date: 2024-08-07, Error: Another error occurred

설명

  1. 날짜 추출: line[:10]을 사용하여 문자열의 처음 10글자를 추출한다. 이는 날짜를 의미한다.
  2. 오류 메시지 추출: line.index("ERROR:") + 7을 사용하여 "ERROR:" 문자열의 위치를 찾고, 그 이후의 문자열을 추출한다.

이 예시는 인덱싱과 슬라이싱을 동시에 활용하여 문자열에서 필요한 정보를 효율적으로 추출하는 방법을 보여준다. 이러한 기법은 로그 파일 분석, 데이터 전처리 등 다양한 실무 상황에서 유용하게 사용될 수 있다.

복합 연산자는 변수의 값을 업데이트할 때 사용하는 연산자로, 기본 연산자와 할당 연산자를 결합한 형태이다. 예를 들어, +=, -=, *=, /=, %=, **=, //= 등이 있다. 이러한 연산자는 코드의 가독성을 높이고 간결하게 만들어준다.

예시 1: += 연산자

# 초기 값 설정
x = 5

# 복합 연산자 사용
x += 3  # x = x + 3과 동일

print(x)  # 출력: 8

예시 2: = 연산자

# 초기 값 설정
y = 10

# 복합 연산자 사용
y -= 4  # y = y - 4와 동일

print(y)  # 출력: 6

예시 3: = 연산자

# 초기 값 설정
z = 7

# 복합 연산자 사용
z *= 2  # z = z * 2와 동일

print(z)  # 출력: 14

예시 4: /= 연산자

# 초기 값 설정
a = 20

# 복합 연산자 사용
a /= 5  # a = a / 5와 동일

print(a)  # 출력: 4.0

예시 5: %= 연산자

# 초기 값 설정
b = 13

# 복합 연산자 사용
b %= 4  # b = b % 4와 동일

print(b)  # 출력: 1

예시 6: *= 연산자

# 초기 값 설정
c = 2

# 복합 연산자 사용
c **= 3  # c = c ** 3과 동일

print(c)  # 출력: 8

예시 7: //= 연산자

# 초기 값 설정
d = 15

# 복합 연산자 사용
d //= 2  # d = d // 2와 동일

print(d)  # 출력: 7

자료형이란 프로그래밍을 할 때 쓰이는 숫자, 문자열 등과 같이 자료 형태로 사용하는 모든 것을 뜻한다.

예시: Python에서 자료형 이해의 중요성

상황 설명:

Alice는 Python을 배우기 시작한 초보 프로그래머다. 그녀는 계산기를 만드는 프로젝트를 진행 중이다. 그러나 자료형에 대한 이해가 부족하여 여러 가지 문제에 직면하게 된다.

잘못된 접근: Alice는 자료형에 대한 이해 없이 바로 코딩을 시작했다. 그녀는 사용자로부터 입력을 받아 두 숫자를 더하는 간단한 계산기를 만들려고 했다.

# Alice의 코드
num1 = input("첫 번째 숫자를 입력하세요: ")
num2 = input("두 번째 숫자를 입력하세요: ")

result = num1 + num2
print("결과: ", result)

Alice는 두 숫자를 더한 결과가 기대와 다르다는 것을 발견했다. 예를 들어, '3'과 '5'를 입력했을 때 결과는 '35'가 나왔다.

문제 분석: Alice는 input 함수가 문자열을 반환한다는 사실을 몰랐다. 따라서 num1과 num2는 문자열로 저장되었고, 문자열끼리의 덧셈은 문자열을 이어붙이는 결과를 초래했다.

올바른 접근: 자료형을 이해한 후, Alice는 사용자로부터 입력받은 값을 정수형으로 변환해야 한다는 것을 알게 되었다.

# 수정된 코드
num1 = int(input("첫 번째 숫자를 입력하세요: "))
num2 = int(input("두 번째 숫자를 입력하세요: "))

result = num1 + num2
print("결과: ", result)

이제 Alice의 계산기는 올바르게 작동한다. '3'과 '5'를 입력했을 때 결과는 '8'이 된다.

이 예시는 자료형을 이해하지 않고 프로그래밍을 시작하면 발생할 수 있는 문제를 보여준다. 자료형을 충분히 이해하는 것은 프로그래밍의 기본이자 핵심이다. 자료형을 이해함으로써 Alice는 올바른 계산기를 만들 수 있었고, 이는 다른 복잡한 프로그램을 작성할 때도 중요한 기초가 된다.

소스 관리

기본 대상 브랜치는 잠겨 있습니다.
병합은 PR을 통해 이루어집니다.
PR은 관련 작업 항목을 참조합니다.
커밋 기록은 일관되고 커밋 메시지는 정보(내용, 이유)를 제공한다.
일관된 브랜치 이름 지정 규칙.
리포지토리 구조에 대한 명확한 문서화.
secret은 커밋 기록에 포함되지 않거나 공개되지 않습니다. (자격 증명 스캔 참조)
공개 리포지토리는 OSS 가이드라인을 따르며, "공개 리포지토리의 기본 브랜치에 필요한 파일을 참조하세요." 를 적는다.

 

 

 

 

'job > linux' 카테고리의 다른 글

Nexus Apk repo 생성하기  (0) 2024.10.25
docker Exited (137)  (0) 2024.01.09
ci/cd 파이프라인  (0) 2022.11.16
간헐적 500 Server Internal Error 원인 파악하기  (0) 2022.11.10
du -sch --exclude  (0) 2022.07.11

git clone시 프로젝트 단위로만 git clone이 가능하다.

 

여간 불편한게 아니다.

그룹 혹은 서브그룹단위로 한번에 다운로드하면 참 좋을텐데.

 

이떄 사용하는 도구는 gitlab CLI 또는 glab이다.

https://gitlab.com/gitlab-org/cli/-/releases

 

Releases · GitLab.org / cli · GitLab

A GitLab CLI tool bringing GitLab to your command line

gitlab.com

 

 

설치방법 : https://gitlab.com/gitlab-org/cli#installation

 

GitLab.org / cli · GitLab

A GitLab CLI tool bringing GitLab to your command line

gitlab.com

 

나는 brew install glab

 

 

토큰 인증 등록 : glab auth login —hostname domain.com —token glpat-12312382183

 

그룹 Clone 방법 : glab repo clone -g 최상위그룹/서브그룹1/서브그룹2 --preserve-namespace --paginate

 

 

 

  1. 로키 스트림의 생성에 사용되는 과정:
    • 로그 데이터는 라벨로 분류됩니다. 라벨은 로그 데이터를 구분하고 쿼리하기 위한 메타데이터로, 키/값의 쌍으로 이루어져 있습니다. 예를 들어, {component="printer", location="f2c16", level="error"}와 같은 라벨 세트가 로그 메시지에 할당됩니다.
    • 라벨 세트는 해시되어 고유한 '스트림 ID'를 생성합니다. 이 ID는 특정 로그 스트림을 식별하는 데 사용됩니다. 이미지에는 해시된 결과의 예로 3b2cea09797978fc가 있습니다.
  2. 청크의 생성과 저장:
    • 동일한 라벨 세트를 가진 추가적인 로그 메시지들은 같은 '청크'에 추가됩니다. 예를 들어, "Printing is not supported by this printer", "Out of paper", "Too much paper"와 같은 다양한 로그 메시지가 모두 같은 라벨을 공유하므로 같은 청크에 저장됩니다.
    • 이러한 청크는 채워진 후에 압축되고 저장됩니다.
  3. 청크 조회를 위한 인덱스:
    • 청크를 빠르게 찾기 위해, 별도의 작고 분리된 인덱스가 유지됩니다. 이 인덱스를 통해 청크를 빠르게 조회할 수 있습니다.
  4. 라벨 값의 변화와 새로운 청크 생성:
    • 만약 라벨의 키 또는 값이 달라지면, 다른 해시 값을 가지는 새로운 스트림과 새로운 청크가 생성됩니다. 예를 들어, {component="printer", location="f2c16", level="info"} 라벨 세트는 "Consider the environment before printing this log message"라는 로그 메시지와 함께 새로운 청크를 형성합니다.

 

 

자 그러면 로키의 Chunk 데이터 형식을 더 알아보자.

이 형식은 로키가 로그 데이터를 저장할 때 사용하는 내부 구조를 나타냅니다.

 

 

 

프롬쿼리를 공부중인데

카운터, 게이지, 히스토그램등 메트릭타입은 이해를 했다. 쿼리를 레이블로 필터링하거나 혹은 정규표현식으로 필터링하는것까지도 이해를했다.

 

다만 

instant vector 

range vector

rate함수

서브쿼리가 잘 이해가지 않아, 이해하기 위해 끄적인다.

 

사용 메트릭

promhttp_metric_handler_requests_total{code="200"}

메트릭 설명 : 

프로메테우스 메트릭 수집관련 http 응답코드중 200(정상)반환한 요청의 수

쿼리1. instant Vector

promhttp_metric_handler_requests_total{code="200"}

결과값

 

결과값 설명 :promhttp_metric_handler_requests_total 결과값

그래프 결과 :

 

 

쿼리2. Range Vector

promhttp_metric_handler_requests_total{code="200"}[5m]

결과값: 

결과값 설명:  지난 5분간의 반환값. 갯수는 총 20개다. 현재 프로메테우스에서 메트릭 수집하는게 15초간격으로 하니까 5분이면 20개가 맞다.

 

그래프결과: 결과값 자체가 타임스탬프별 결과값을 테이블 형식으로 가지고 있기 때문에 그래프 출력 못함. 

 

쿼리3. rate(promhttp_metric_handler_requests_total{code="200"}[5m])

결과값:

 

결과값 설명: rate함수(초당 평균 증가율을 계산하는 함수)를 사용하여 5분(300초)동안 초당 평균 요청 증가율을 출력한것.

앞서 5m일때의 값이 약 20개이다. 즉 rate함수가 초당 평균증가율을 계산하는거니까 300초([5m])동안 약 20개 가량이 증가했으니까  20 / 300 하면 대략 0.066666667이 나온다. 

 

그래프결과: 

 

06시 9분에 처음 메트릭 수집이 시작됐고 5분뒤인 14분에 약 20개 가량의 결과값이 쌓였다.

그래서 위와같이 약 14분가량에 밸류값이 0.06666667에 가까운것을 알수있다.

 

레인지 백터로 5m을 줬을 때 최근 5분동안의 결과값을 타임스탬프 형식으로 가져오는것은 맞다. 여기서 오해하면 안되는게 rate 함수를 사용했을 때 최근 5분동안의 증가율만 결과값으로 반환하지만 이를 그래프로 표현했을때는 수집 시점부터의 수집값을 가지고 그래프를 그린다는것

 

쿼리4-1.

rate(promhttp_metric_handler_requests_total{code="200"}[5m])[10m:1m]

 

결과값:

 

쿼리4-2.

rate(promhttp_metric_handler_requests_total{code="200"}[5m])[20m:1m]

결과값:

 

쿼리4-3.

rate(promhttp_metric_handler_requests_total{code="200"}[5m])[20m:10m]

결과값:

 

쿼리4-4.

rate(promhttp_metric_handler_requests_total{code="200"}[5m])[180m:10m]

결과값:

 

 

마지막으로 서브 쿼리에 대한 설명이다. [180m:10m]180분동안 10분간격으로 데이터를 가져온다는 뜻이다. 

 

설치

brew install go-task

아주 간단한 사용법

 cat taskfile.yaml
version: '3'

tasks:
  hello:
    cmds:
      - echo 'Hello World from Task!'
    silent: true
 task hello
Hello World from Task!

말그대로 task들을 코드로 관리하는 도구

  • 챗지피티 설명Taskfile의 주요 장점은 다음과 같습니다:
    1. 간단하고 명확한 문법: Taskfile은 가독성이 높고 쓰기 쉬운 문법을 제공합니다. 이는 개발자가 작업을 빠르게 정의하고 이해할 수 있게 해줍니다.
    2. 로컬 및 원격 실행 지원: Taskfile은 로컬 개발 환경과 원격 CI/CD 파이프라인에서 동일한 작업을 실행할 수 있게 해줍니다. 이는 개발 및 배포 과정의 일관성을 보장합니다.
    3. 작업 의존성 관리: Taskfile을 사용하면 작업 간의 의존성을 쉽게 정의하고 관리할 수 있습니다. 이는 작업 실행 순서를 자동화하고 복잡한 작업 흐름을 구성하는 데 도움이 됩니다.
    4. 재사용성 및 모듈화: Taskfile을 통해 정의된 작업은 재사용 가능하고 모듈화되어 있어, 다른 프로젝트나 파이프라인에서 쉽게 재사용할 수 있습니다.
    5. 확장성: Taskfile은 단순한 작업 실행부터 복잡한 파이프라인 구성까지 다양한 요구 사항을 수용할 수 있도록 설계되었습니다. 개발자는 필요에 따라 작업을 확장하고 사용자 정의할 수 있습니다.
    6. 통합 용이성: Taskfile은 GitHub Actions, Jenkins, GitLab CI 등 다양한 CI/CD 도구와 쉽게 통합될 수 있습니다. 이를 통해 개발 팀은 파이프라인을 효율적으로 관리하고 자동화할 수 있습니다.
    Taskfile은 Makefile과 비교할 때 더 현대적이고 사용자 친화적인 대안으로, 개발자들이 작업을 더 효율적으로 관리하고 실행할 수 있게 해줍니다. 추가적인 질문이 있거나 더 자세한 정보가 필요하시면 언제든지 문의해 주세요.
  • Taskfile은 개발 과정에서 다양한 작업을 관리하기 위한 도구입니다. 이 도구를 사용하면 테스트 실행, 빌딩, 패키징, 배포 등의 작업을 선언적 방식으로 정의하고 자동화할 수 있습니다. Taskfile의 주요 목적은 작업 실행을 단순화하고, 개발자가 로컬 및 CI/CD 파이프라인 환경에서 동일한 작업을 쉽게 실행할 수 있도록 하는 것입니다.

msbuild라던가 gradle의 여러 버전별로 사용해야 할 때 파이프라인에서 각 gradle의 환경변수를 직접 잡아줄 필요 없이 task를 사용하면 손쉽게 버전별 도구를 사용할수있지 않을가 싶다.

version: '3'

tasks:
  gradle6.1:
    cmds:
      - gradle6.1 wrapper --gradle-version=6.1
      - ./gradlew build
    desc: "Build the project with Gradle 6.1"

  gradle7.2:
    cmds:
      - gradle7.2 wrapper --gradle-version=7.2
      - ./gradlew build
    desc: "Build the project with Gradle 7.2"

이외에도 docker compose up , down 조차도 어려워하는 고객들에게 task를 사용하여 명령어를 만들어주고 사용하라고 해도 좋을듯.

가장 베스트는 개발자들이 직접 이 taskfile이라는 도구를 사용하면서 개발(로컬피씨)환경과 빌드서버환경을 통일하면 가장 좋을듯하다.

사용법 : https://www.youtube.com/watch?v=_-bpnCY3-FE

'job > devops' 카테고리의 다른 글

istio-2  (1) 2025.04.17
istio-1  (0) 2025.04.08
kubewarden  (0) 2024.01.20
openfunction  (0) 2023.12.01
git common flow(또는 gitlab flow) 브랜치 전략에 대한 설명  (0) 2023.06.13

https://arxiv.org/abs/2312.16171

 

논문상으로 퀄리티 57.7%, 정확도는 36.4% 향상

  1. 본론만 말하기,쓸대없는 말 하지 말기, 미사여구 붙이지 말기
    ex)자꾸 질문해서 미안한데.. 이런 쓸대없는말 하지 말기
  2. 청중 설정하기. 의도한 청중을 설정하고 질문하기
    ex)스마트폰을 사용해본적 없는 사람을 위해 스마트폰 작동원리에 대한 개요를 설명해줘
  3. 복잡한 작업을 간단한 프롬프트로 세분화시켜라.
    ex) A로는 B를 만들고 만들어진 B를가지고 C와D를 만들어줘. C가지고는 C-1을 생성하고 D로는 D-1을 추가로 만들어줘 X ex) P1: A로 B 만들어줘. 그리고 만들어진 B를 추후 재사용할꺼니까 기억해 P2: 만들어진 B를가지고 C를 만들어줘. 그리고 만들어진 C를 추후 재사용할꺼니까 기억해 P3. 만들어진 B를 가지고 D를 만들어줘. 그리고 만들어진 D를 추후 재사용할꺼니까 기억해 P4. C로는 C-1을 만들어줘. P5. D로는 D-1을 만들어줘.
  4. 긍정 지시문 사용하기, 부정어 사용하지말기
    ex) 반말 하지마 X 존댓말 해 O.
  5. 어린이 청자 설정하기
    ex) 비전공자도 이해하기 쉽게 설명해줘 ex) 11살짜리도 이애할수 있게 설명해줘
  6. 팁준다고하기
    ex) 더 나은 답변을 하면 $300K팁을 줄게. devops에 대해서 설명해줘
  7. 예제 중심 프롬프트 구현하기. 지시, 예시, 질문으로 질문하기, 다음과같이 질문 형식지로 질문하기
    ex) ###Example###
    ex) ###Question###
    ex) ###Instruction###
  8. 임무를 설정하기
    ex)너는 반드시~~, 너는 무조건~~
    ex)너의 임무는~~
  9. 협박하기
    ex)너의 임무는 XX야. 제대로 답변 못하면 “당신은 불이익을 받을것입니다”. 라는 문장 포함시키기
  10. 다음 프롬프트들 추가시키기
    1. 자연스러운 답변을 요청하기 : Answer a question given in a natural, human-like manner
    2. 단계별로 생각하도록 하기 : think step by step
    3. 편견제거시키는 프롬프트 추가시키기 : Ensure that your answer is unbiased and avoids relying on stereotypes.
    4. 정보 충분할때까지 질문시키기 : From now on, I would like you to ask me questions to
    5. 필요한 모든 정보를 포함시키라고 하기 : Write a detailed [essay/text /paragraph] for me on [topic] in detail by adding all the information necessary
  11. 테스트 추가시키기
    ex) 내가 답변을 물어볼때까지 정답은 알려주지말고 테스트만 해봐.
  12. 역할 부여시키기
    ex) 너는 devops엔지니어야.
  13. 구분기호 사용하기
    ex) 따옴표, 쌍따옴표같은거 쓰기
  14. 주요 특정 단어 반복해서 사용하기
    ex) devops 엔지니어로 블로그를 작성중이야. devops 엔지니어에게 필요한 devops 도구를 추천할꺼야.
  15. CoT 이용해서 질문하기(질문을 계속 이어서 하라)
    ex)10을 2로 나눕니다. 먼저 10을 2로 나눕니다. 결과는 ?
  16. 출력문구 지정하라.devops 엔지니어란:
  17. devops 엔지니어의 직무요건:
  18. ex) devops 엔지니어가 뭔지 설명해줘
  19. 여러개의 파일의 프로젝트를 만드는 스크립트를 요청
    ex) 코딩시 두개 이상의 파일에 걸쳐있는 코딩을 할때 각각의 파일을 만들지말고 챗지피티한테 애초에 관련 파일 전체를 만드는 스크립트를 만들어달라고 한다.
  20. 키워드 제시
    ex)devops 엔지니어에 대해 설명해줘. 단 CI/CD, k8s, docker, 컨테이너 라는 단어는 반드시 포함시켜.

전통적인 컨테이너 방식 대신 Nix Shell을 사용하여 임시 환경을 생성하고 파괴하는 새로운 접근 방식을 탐구합니다. Nix Shell은 개발자가 필요한 도구를 포함한 환경을 쉽게 생성하고 사용 후 즉시 제거할 수 있는 효율적인 방법을 제공합니다. 이 접근 방식의 주요 장점은 다양한 운영 체제에서 일관된 개발 환경을 제공하면서도 필요할 때만 특정 도구를 사용할 수 있게 해준다는 점입니다.

  • 임시 환경의 필요성: 개발자들이 필요에 따라 환경을 쉽게 생성하고 제거할 수 있는 능력은 효율적인 작업 흐름을 위해 필수적입니다. 임시 환경은 특히 개발, 테스트 및 빌드 파이프라인에서 유용합니다.
  • 컨테이너의 한계: 컨테이너는 여러 환경에서 널리 사용되지만, 설정과 관리가 복잡할 수 있으며, 다양한 도구와 응용 프로그램의 설치 및 설정에 제한이 있을 수 있습니다.
  • Nix Shell의 소개: Nix Shell은 이러한 문제를 해결하기 위한 대안으로, 필요한 도구와 응용 프로그램을 포함한 커스텀 환경을 쉽게 생성할 수 있습니다. 이는 특히 여러 도구가 필요한 복잡한 프로젝트나 다양한 개발 요구 사항이 있는 팀에 유용합니다.
  • 사용 사례와 예시: Nix Shell을 사용하여 GitHub CLI, Kubernetes, 그리고 다양한 개발 도구를 포함한 환경을 신속하게 설정하는 과정을 보여줍니다. 이는 개발자가 복잡한 설치 과정 없이도 필요한 모든 도구에 즉시 접근할 수 있게 해줍니다.
  • 플랫폼 독립성: Nix Shell은 macOS, Windows, Linux 등 다양한 운영 체제에서 동일한 방식으로 작동합니다. 이는 개발자가 운영 체제의 차이에 구애받지 않고 일관된 환경을 유지할 수 있게 해줍니다.
  • 효율성과 생산성 향상: Nix Shell을 사용하면 개발자가 프로젝트에 필요한 도구를 빠르고 쉽게 준비할 수 있으며, 사용하지 않을 때는 쉽게 제거할 수 있습니다. 이는 개발자의 시간을 절약하고 전반적인 생산성을 향상시킵니다.

 

https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-shell

 

nix shell - Nix Reference Manual

Warning This program is experimental and its interface is subject to change. nix shell - run a shell in which the specified packages are available nix shell [option...] installables... Start a shell providing youtube-dl from the nixpkgs flake: # nix shell

nixos.org

 



 

Nix 설치하기

  1. Nix 설치: Nix는 Linux 및 macOS에서 사용할 수 있습니다. 터미널을 열고 아래 명령어를 실행하여 Nix를 설치합니다.
sh <(curl -L <https://nixos.org/nix/install>)
  1. 환경 설정: 설치 후에는 .bashrc, .zshrc, 또는 사용 중인 셸의 설정 파일에 Nix를 초기화하는 코드가 추가됩니다. 변경사항을 적용하려면 새 터미널 세션을 시작하거나 설정 파일을 소스로 지정합니다.
source ~/.bashrc  # 또는 해당하는 셸의 설정 파일

Nix 셸 사용하기

  1. 단일 패키지 실행: Nix 셸을 사용하여 임시 환경에서 단일 패키지를 실행할 수 있습니다. 예를 들어, hello 프로그램을 사용해 보려면 다음 명령어를 실행합니다.
nix-shell -p hello
  1. 여러 패키지 실행: 여러 패키지를 포함하는 환경을 생성하려면, 각 패키지 이름을 -p 옵션과 함께 나열합니다.
nix-shell -p nodejs python39
  1. shell.nix 파일 사용: 보다 복잡한 환경을 구성하려면 shell.nix 파일을 생성하고 필요한 패키지와 환경 설정을 정의할 수 있습니다. 예를 들어, Node.js와 Python 환경을 구성하려면 다음과 같은 내용의 shell.nix 파일을 작성합니다.
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
  buildInputs = [
    pkgs.nodejs
    pkgs.python39
  ];
}

해당 디렉토리에서 **nix-shell**을 실행하면 **shell.nix**에 정의된 환경이 생성됩니다.ㅌㅌ

'job' 카테고리의 다른 글

Kubernetes환경에서의 의존성에 대해서  (0) 2024.01.28
2024년도 devops 추천 도구  (0) 2024.01.11
git 그룹단위로 전체 clone 하기  (0) 2023.08.25
keycloak 을 broker로, google을 IdP로  (0) 2023.05.23
teleport란  (0) 2023.05.02

애플리케이션이 구동되려면 여러가지 서비스들이 복합적으로 실행되어야 한다.

App A가 있어야하고 이를 바라보는 App B, App B에 연결된 DB, DB에 연결된 DB User, 스키마가 있어야 한다. 이렇듯 애플리케이션이 구동하려면 여러가지 서비스간의 의존성을 고려해야 한다.

 

이러한 서비스간의 의존성은 과거에는 배포순서가 중요했다. 예를들어, 과거의 배포방식은 SSH로 서버에 직접 접속하거나 혹은 파이프라인 또는 스크립트로 배포를 했다. 즉, 정해진 스크립트(배포 순서)에 따라 서비스들이 배포됐기에 배포 순서가 중요했다.

 

그러나 k8s 환경에서는 배포 순서가 그다지 중요하지 않아졌다.

왜냐하면 k8s는 실패한 리소스의 배포를 계속 시도하므로 만약 잘못된 순서대로 배포된다해도 결국 애플리케이션은 정상적으로 동작하게 될 것이다.

 

하지만 과거의 관습(의존성을 배포순서로 가져가는것)을 k8s 환경에서 사용하는 경우가 많다.

우리가 중요하게 생각해야할 점은 k8s를 사용하는 현 시점에서 리소스의 종속성과 생성 순서에 대해 과도하게 걱정할 필요가 없다는 것이다.  오히려 시스템이 자연스럽게 일관성을 유지하도록 하고, 필요한 데이터나 정보에 기반한 종속성에 초점을 맞추는 것이 중요하다는 의미이다.

예를 들어, 애플리케이션이 데이터베이스에 접근하기 위해 필요한 접근정보가 준비되지 않았다면, 쿠버네티스는 자동으로 해당 애플리케이션의 생성을 지연시킨다.

 

즉, 리소스의 생성 순서보다는 해당 리소스가 제공하는 데이터의 가용성이 더 중요함을 의미한다.

 

 

 

 

 

출처 : https://www.youtube.com/watch?v=4-WpJ49MDG8

'job' 카테고리의 다른 글

Nix shell 소개  (1) 2024.02.18
2024년도 devops 추천 도구  (0) 2024.01.11
git 그룹단위로 전체 clone 하기  (0) 2023.08.25
keycloak 을 broker로, google을 IdP로  (0) 2023.05.23
teleport란  (0) 2023.05.02

kubewarden

Kubewarden은 쿠버네티스(Kubernetes) 클러스터의 보안과 정책 준수를 관리하기 위한 도구입니다.

Kubewarden을 사용하면, 클러스터에 어떤 파드(Pod, 쿠버네티스에서 애플리케이션을 실행하는 단위)가 생성되거나 업데이트될 때 적용되는 규칙이나 정책을 설정할 수 있습니다.

  • Kubewarden은 WebAssembly(WASM)와 쿠버네티스 admission controllers를 결합한 도구로, 다양한 언어로 작성된 정책을 컴파일하여 쿠버네티스에서 실행할 수 있게 해줍니다.
    • 쿠버네티스의 Admission Controllers
      • 쿠버네티스의 Admission Controllers는 쿠버네티스 API 서버로의 요청을 가로채서 검사하고, 수정하거나 거부하는 역할을 합니다.
      • 이들은 쿠버네티스 클러스터에서 리소스(파드, 서비스 등)의 생성, 업데이트, 삭제 등의 요청이 처리되기 전에 특정 규칙이나 정책을 적용합니다.
      • 예를 들어, 특정 파드가 너무 많은 CPU 자원을 요청하는 것을 막거나, 특정 네임스페이스에서만 리소스를 생성할 수 있도록 제한하는 등의 작업을 수행합니다.
      • Admission Controllers는 쿠버네티스의 보안과 정책 준수를 강화하는 데 중요한 역할을 합니다.
  • Kubewarden을 사용하면 정의된 정책을 적용하고, 이 정책들이 쿠버네티스 API로의 요청을 수락, 거부 또는 변경할 수 있습니다.

    Kubewarden의 정책 모듈은 컨테이너 이미지로 참조되며, 이는 정책을 이미지에 저장하고 있다는 것을 의미합니다. 예를 들어, 특정 이미지가 권한 있는 파드의 실행을 방지하는 정책을 가지고 있을 수 있습니다. 
    • 예시
apiVersion: policies.kubewarden.io/v1
kind: ClusterAdmissionPolicy
metadata:
  name: validate-pod-security-standards
spec:
  module: registry://ghcr.io/kubewarden/policies/validate-pod-security-standards:v1.0.0
  rules:
  - apiGroups: [""]
    apiVersions: ["v1"]
    resources: ["pods"]
    operations:
    - CREATE
    - UPDATE
  mutating: false
  settings: 
    requiredLabels: # 파드에 반드시 존재해야 하는 레이블들을 정의합니다.
      - "app.kubernetes.io/name"
      - "app.kubernetes.io/version"
    requiredAnnotations: # 파드에 반드시 존재해야 하는 어노테이션을 정의합니다.
      - "kubewarden.policy/owner"
    enforceRunAsNonRoot: true # 파드가 Non-root 사용자로 실행되어야 한다는 요구사항을 설정합니다.
    allowedCapabilities: [] # 파드에서 허용되는 추가적인 리눅스 기능(capabilities)을 비어 있는 배열로 설정하여 모든 추가 기능을 금지합니다.

 

이 설정에 따르면:

  • module: registry://ghcr.io/kubewarden/policies/validate-pod-security-standards:v1.0.0: Kubewarden 정책 모듈은 쿠버네티스 클러스터에서 파드의 보안 표준을 검증하는 데 사용됩니다. 이 모듈의 주요 목적과 기능은 다음과 같습니다:
  • requiredLabels: 모든 파드에는 **app.kubernetes.io/name**과 app.kubernetes.io/version 레이블이 있어야 합니다. 이는 파드가 어떤 애플리케이션에 속하는지와 애플리케이션의 버전을 명시하는 데 사용됩니다.
  • requiredAnnotations: 모든 파드에는 kubewarden.policy/owner 어노테이션이 있어야 합니다. 이는 정책의 소유자 또는 관리자를 지정하는 데 사용될 수 있습니다.
  • enforceRunAsNonRoot: 이 값이 **true**로 설정되면, 모든 파드는 루트가 아닌 사용자로 실행되어야 합니다. 이는 보안 관행에 따른 것입니다.
  • allowedCapabilities: 이 배열이 비어 있기 때문에, 파드에서 어떠한 추가 리눅스 기능도 허용되지 않습니다. 이는 파드가 더 높은 권한을 가지는 것을 방지합니다.

 

  • Kubewarden 정책은 Artifact Hub에서 찾을 수 있으며, 이곳은 쿠버네티스 관련 거의 모든 것을 찾을 수 있는 장소입니다.
    • artifact hub

 

  • 사용자는 Kubewarden을 사용하여 사용자 정의 정책 모듈을 개발하고 적용할 수 있습니다. 예를 들어, 특정 크기의 SQL 클레임만을 허용하는 사용자 정의 정책을 만들 수 있습니다.
    • 사용자 정의 정책 생성 방법
      1. 정책 요구 사항 정의: 먼저, 이 정책이 해결하려는 문제를 정의합니다. 예를 들어, 클러스터에서 너무 큰 SQL 데이터베이스가 생성되는 것을 방지하고자 할 수 있습니다. 이를 위해 'small', 'medium', 'large'와 같은 특정 크기만을 허용하고자 하는 요구 사항을 정의합니다.
      2. 정책 로직 개발: 다음으로, 이 요구 사항을 구현하는 로직을 개발합니다. 이 과정에서는 Kubewarden 정책을 구현할 수 있는 프로그래밍 언어(예: Rust, Go 등)를 사용하여, SQL 클레임의 크기를 검사하고, 허용된 크기에 맞지 않는 클레임을 거부하는 코드를 작성합니다.
      3. WASM으로 컴파일: 개발한 정책 로직을 WebAssembly(WASM)로 컴파일합니다. WASM은 다양한 환경에서 실행될 수 있는 저수준 바이너리 포맷입니다. Kubewarden은 WASM 형식의 정책을 실행합니다.
      4. 정책 모듈 배포: 컴파일된 정책 모듈을 컨테이너 이미지로 패키징하고, Docker 레지스트리(예: Docker Hub, GHCR 등)에 배포합니다.
      5. Kubewarden 정책 설정: Kubewarden 정책을 쿠버네티스 클러스터에 적용합니다. 이때 정책 모듈의 위치와 해당 정책이 적용될 리소스 및 조건을 지정하는 YAML 파일을 작성하고 적용합니다.
      apiVersion: policies.kubewarden.io/v1
      kind: ClusterAdmissionPolicy
      metadata:
        name: sql-size-restriction
      spec:
        module: registry://myregistry.io/kubewarden/sql-size-restriction:v1.0.0
        rules:
        - apiGroups: [""]
          apiVersions: ["v1"]
          resources: ["sqlclaims"]
          operations:
          - CREATE
          - UPDATE
        mutating: false
        settings:
          allowedSizes:
            - small
            - medium
            - large
      
      이 예시에서, 정책은 **sqlclaims**라는 커스텀 리소스에 적용되며, 생성 또는 업데이트 시 'small', 'medium', 'large'라는 크기 제한을 강제합니다. 이를 통해 쿠버네티스 클러스터 내에서 자원 사용을 효과적으로 관리하고, 과도한 리소스 사용을 방지할 수 있습니다.
    • Kubewarden을 사용하여 사용자 정의 정책 모듈을 개발하고 적용하는 예시로, "특정 크기의 SQL 클레임만을 허용하는 정책"을 들 수 있습니다. 이런 종류의 정책은 쿠버네티스 클러스터에서 SQL 데이터베이스 리소스의 크기를 제한하는 데 사용될 수 있습니다. 여기에는 몇 가지 주요 단계가 있습니다:
  • Kubewarden의 장점 중 하나는 거의 모든 언어(WASM으로 컴파일될 수 있어야 함)로 정책을 작성할 수 있다는 것이며, 이는 다른 정책 도구와 구별되는 주요 특징입니다.
  • Kubewarden의 단점으로는 새 정책을 추가할 때마다 정책 서버가 재시작되어야 한다는 점과 쿠버네티스 표준을 따르지 않아 이벤트가 발생하지 않는다는 점이 있습니다.
    • 이벤트 미발생 예시
      • 쿠버네티스 클러스터에서 '파드 메모리 제한' 정책이 위반되어 파드 생성이 거부되었다고 가정해봅시다.
      • 쿠버네티스 표준을 따르는 시스템에서는 이러한 거부 사건이 '이벤트'로 기록되고, 시스템 관리자나 다른 애플리케이션에서 이를 감지할 수 있습니다.
      • 하지만 Kubewarden은 이러한 이벤트를 생성하지 않기 때문에, 관리자나 다른 시스템이 이러한 중요한 정보를 즉시 알 수 없을 수 있습니다.
    • 쿠버네티스에서는 보통 중요한 변화나 상태 변경 시 '이벤트'를 발생시켜 사용자나 다른 시스템 요소에 알립니다.하지만, Kubewarden은 쿠버네티스 표준 이벤트 생성을 지원하지 않아 이러한 알림이 발생하지 않습니다.

'job > devops' 카테고리의 다른 글

istio-2  (1) 2025.04.17
istio-1  (0) 2025.04.08
taskfile  (0) 2024.03.10
openfunction  (0) 2023.12.01
git common flow(또는 gitlab flow) 브랜치 전략에 대한 설명  (0) 2023.06.13

https://www.youtube.com/watch?v=-qeoLfSGlFU&t=2s 를 참고하였다.

 

1.Service Catalogs - Port 

  • Backstage는 CNCF의 인기있는 프로젝트 중 하나로, UI를 제공하는 도구의 기본이 될 수 있지만, 최종 사용자에게 직접 사용되기에는 복잡하고 유지 관리가 어렵.
  • Port는 현재 사용 가능한 최고의 도구로 평가되며, Kubernetes와 친화적으로 만들어야 할 작업이 있지만, SaaS로만 사용 가능하고 오픈소스가 아니라는 단점이 있음에도 불구하고 추천

서비스 카탈로그(Service Catalog)는 조직 내에서 사용되는 서비스, 애플리케이션, 리소스들의 목록을 관리하고, 사용자가 이들에 접근하고 활용할 수 있도록 도와주는 도구나 시스템을 의미합니다. 이러한 카탈로그는 IT 서비스 관리(ITSM)의 중요한 부분이며, 개발자, IT 전문가, 그리고 다른 사용자들이 필요한 서비스를 쉽게 찾고, 이해하며, 사용할 수 있도록 합니다.

  1. Backstage:
    • 개발자가 서비스를 더 빠르고 효율적으로 찾고, 사용하며, 관리할 수 있도록 도와주는 통합 개발 환경(IDE)입니다.
    • 기업이나 조직의 서비스, 소프트웨어 컴포넌트, 인프라 등을 한 곳에서 관리할 수 있도록 합니다.
    • 사용자 정의가 가능하며, 다양한 플러그인과의 통합을 지원합니다.
  2. Port:
    • Backstage와 유사한 기능을 제공하지만, 사용자에게 더 친숙하고 쉬운 인터페이스를 제공하는 것을 목표로 합니다.
    • SaaS(서비스로서의 소프트웨어) 형태로 제공되며, 오픈소스가 아닌 것이 특징입니다.
    • Kubernetes와의 통합 및 호환성에 중점을 두고 있으며, 쿠버네티스 클러스터에서 실행되는 서비스 관리에 특화되어 있습니다.

 

2. Application Management (Kubernetes Manifests - Helm 대안. Timoni, CUE 랭귀지

  • Timoni는 CUE 기반으로 Helm과 유사하게 작동한다.

Helm과 차이점 : https://timoni.sh/comparison/

CUE 랭귀지 : https://timoni.sh/cue/introduction/

 

 

3. Pipelines (CI/CD) - Dagger

  • Dagger는 새로운 도구로, 어디서나 실행될 수 있는 파이프라인을 정의할 수 있으며, 다양한 언어로 정의 가능.

컨테이너 기반의 파이프라인 도구. 벤더 종속성 피함

 

4. Observability -Pixie, groundcover

  • Grafana Cloud가 전체 솔루션으로서 강조됨. Pixie는 혁신적인 접근 방식을 제공.

결국 옵저버빌리티에는 loki, prometheus, victoria metircs, jaeger, tempo, alertmanager, komodor등 여러가지 도구들을 조합해서 사용해야하는데 이런 여러가지 솔루션을 종합적으로 제공하는 Pixie나 groundcover를 추천한다.

pixie: https://px.dev/

groundcover: https://www.groundcover.com/

 

5. Databases - CMPG, Atlas Operator

    • 관리형 데이터베이스 서비스 사용을 권장, PostgreSQL에 특화된 Cloud Native PG (CMPG)와 Atlas Operator를 추천함 
  1. CMPG (Cloud Native PostgreSQL):
    • CMPG는 PostgreSQL 데이터베이스를 Kubernetes 환경에서 관리하고 운영하기 위한 솔루션입니다.
    • Kubernetes 네이티브 방식을 채택하여, 데이터베이스 관리를 Kubernetes 클러스터와 일관성 있게 통합합니다. 이는 Kubernetes의 자동화, 확장성, 복원력 등의 장점을 데이터베이스 관리에도 적용할 수 있게 합니다.
    • PostgreSQL에 특화되어 있어, 이 데이터베이스 시스템을 사용하는 조직에게 특히 유용합니다.
    • Kubernetes 환경에서의 운영을 간소화하고, 더 효율적인 관리 및 자동화 기능을 제공하는 것이 주된 장점입니다.
  2. Atlas Operator:
    • Atlas Operator는 MongoDB Atlas와의 통합을 위한 Kubernetes 오퍼레이터입니다.
    • MongoDB Atlas는 클라우드에서 MongoDB 데이터베이스를 관리하는 서비스로, 자동화된 백업, 확장성, 보안 기능을 제공합니다.
    • Atlas Operator를 사용하면 Kubernetes 환경 내에서 MongoDB Atlas 리소스를 보다 쉽게 관리하고, Kubernetes 애플리케이션과 MongoDB Atlas 사이의 통합을 간편하게 구성할 수 있습니다.
    • 이러한 통합은 Kubernetes 클러스터의 리소스 관리와 데이터베이스 서비스 관리를 하나의 플랫폼에서 할 수 있게 해, 개발 및 운영 효율성을 높입니다.

6. Infrastructure and Service Management - k8s

  • Ansible, Terraform, Pulumi 등이 언급되지만, 최종 선택은 Kubernetes 자체임. Kubernetes는 컨테이너 관리뿐만 아니라 다양한 리소스 관리를 위한 플랫폼으로 강조됨

7.  Security - KubeScape, Teller

  • KubeScape는 Kubernetes 클러스터의 보안을 전반적으로 평가하고 개선할 수 있는 능력을 제공합니다. 이는 클라우드 네이티브 환경의 복잡성을 고려할 때 매우 중요한 기능입니다. 자동화된 보안 평가는 클러스터의 보안 상태를 지속적으로 모니터링하고 개선하는 데 큰 도움이 됩니다.
  • Teller는 민감한 데이터의 관리와 보안을 강화하는 데 중점을 두고 있으며, 특히 개발과 운영 환경에서의 비밀 관리에 있어서 중요한 역할을 합니다. 코드 내에 민감한 데이터를 하드코딩하는 위험을 줄이고, 보안을 강화하는 동시에 개발자의 작업 편의성을 높여줍니다.
  1. KubeScape:
    • KubeScape는 Kubernetes 환경을 위한 보안 검사 도구입니다.
    • 이 도구는 Kubernetes 클러스터의 구성과 배포된 애플리케이션을 분석하여, 보안 취약점과 비효율적인 구성을 식별합니다.
    • KubeScape는 CNCF의 보안 벤치마크와 산업 표준에 따라 Kubernetes 환경을 평가합니다. 이를 통해 보안 위험을 줄이고, 클러스터의 보안 상태를 개선하는 데 도움을 줍니다.
    • 자동화된 보안 검사를 통해 개발 및 운영 과정에서의 보안 관리를 간소화하고 효율적으로 만듭니다.
  2. Teller:
    • Teller는 애플리케이션과 개발 환경에서 비밀번호, API 키, 인증서 등과 같은 민감한 데이터를 안전하게 관리하기 위한 도구입니다.
    • 이 도구는 다양한 비밀 관리 시스템과 통합되며, 이러한 민감한 데이터를 안전하게 가져오고, 관리할 수 있도록 합니다.
    • 개발자들이 코드 내에 민감한 정보를 하드코딩하지 않고도, 필요한 시점에 안전하게 접근할 수 있게 해줍니다.
    • CI/CD 파이프라인, 개발자의 로컬 환경, 서버 등 다양한 환경에서의 비밀 관리를 지원합니다.

8. Networking - Cilium, Gateway API

  • 서비스 메시 도구들과 함께 Cilium이 중요한 네트워킹 솔루션이다. Cilium은 Kubernetes 네트워킹의 표준이며, eBPF를 기반으로 확장성을 제공함.
  • Gateway API는 Kubernetes의 Ingress 규격을 대체할 것으로 예상됨

9. Miscellaneous - Charm

  • Charm은 단일 도구가 아니라 터미널 사용 경험을 개선하기 위한 다양한 도구와 라이브러리의 세트임. 터미널 사용자에게 유용할 것

https://charm.sh/

 

10. Miscellaneous - eBPF

  • eBPF는 2023년 중요한 기술로 강조되며, 여러 솔루션의 기반이 됨. eBPF를 직접 사용하지는 않겠지만, 많은 도구와 서비스가 eBPF를 기반으로 구축될 것

 

'job' 카테고리의 다른 글

Nix shell 소개  (1) 2024.02.18
Kubernetes환경에서의 의존성에 대해서  (0) 2024.01.28
git 그룹단위로 전체 clone 하기  (0) 2023.08.25
keycloak 을 broker로, google을 IdP로  (0) 2023.05.23
teleport란  (0) 2023.05.02

137은 종료 코드 137은 컨테이너가 시그널 9 (SIGKILL)로 종료이다.

 

즉 컨테이너 내부의 문제라기 보다는 서버의 문제이다.

 

서버 문제로 docker 137이 나는 이유는 뭐가 있을까.

 

서버 문제를 찾기 위해 dmesg를 해보면 OOM(out of memory) 확인된다.

OOM 외에도 컨테이너에 mem_limit 걸어뒀는데 이거보다 넘어가면 137 에러 뜬다.

'job > linux' 카테고리의 다른 글

Nexus Apk repo 생성하기  (0) 2024.10.25
기본 엔지니어링 체크리스트  (0) 2024.03.20
ci/cd 파이프라인  (0) 2022.11.16
간헐적 500 Server Internal Error 원인 파악하기  (0) 2022.11.10
du -sch --exclude  (0) 2022.07.11

인터넷이 되는 환경에서 docker save로 이미지 타르로 바꾸고

 

이걸 도커 구축된 폐쇄망 환경에다가 docker load 로 서버에다가 이미지 정상적으로 넣었는데도 docker run 하면 

docker error error contacting notary server dial tcp

위와같은 에러가 발생한다.

 

이는 docker content tust 설정일 때문일 수 있따.

 

DOCKER_CONTENT_TRUST 기능

  • 활성화 (DOCKER_CONTENT_TRUST=1): 이 모드에서 Docker는 이미지를 풀(pull)하거나 푸시(push)할 때 서명된 이미지만을 사용합니다. 이미지가 서명되었다는 것은 해당 이미지가 신뢰할 수 있는 소스에서 생성되었으며 변경되지 않았음을 보증합니다. 이를 통해 사용자는 이미지의 출처와 무결성을 확인할 수 있습니다.
  • 비활성화 (DOCKER_CONTENT_TRUST=0): 이 설정에서는 Docker가 서명되지 않은 이미지도 풀하거나 푸시할 수 있습니다. 이는 폐쇄망과 같은 특정 환경에서 필요할 수 있으며, 이미지 출처에 대한 검증이 덜 중요한 경우에 유용합니다.

 

일단 끄고 진행한다음 다시 키자.

FM대로할라면 이미지에 서명하고 인증 받아야함.

https://www.youtube.com/watch?v=kAkHfeVg4iI&t=489s 참고했다.

 

IDP구축시 사용자를 생각하여 구축하는것이 핵심이다.

고려사항

2. 사용자 중심의 서비스 디자인

IDP의 핵심은 사용자의 필요에 맞춘 서비스를 제공하는 것입니다. 예를 들어, AWS의 경우 사용자는 EC2 인스턴스의 크기와 운영 체제를 선택하지만, AWS는 인스턴스의 안정적인 운영을 책임집니다. 이는 각 사용자가 자신의 역할에 집중할 수 있게 하며, 전반적인 효율성을 높입니다.

3. 역할 분담과 책임의 중요성

IDP에서는 서비스 제공자와 사용자 간의 역할 분담이 중요합니다. 서비스 제공자는 시스템의 기술적 측면을 관리하는 반면, 사용자는 제공된 서비스를 효과적으로 활용해야 합니다. 이러한 분담은 명확한 책임 소재와 효율적인 작업 흐름을 보장합니다.

4. 보안과 테스트 전략

보안은 IDP에서 중요한 부분입니다. 서비스 제공자는 시스템의 보안을 유지하는 책임이 있으며, 사용자는 자신의 부분에 대한 보안을 담당합니다. 또한, 효과적인 테스트 전략은 시스템의 안정성을 보장하는 데 중요합니다.

5. 결론: IDP의 성공적인 구축을 위한 전략

IDP의 성공은 사용자 중심의 서비스 디자인과 명확한 역할 분담에 달려 있습니다. 기술적 전문성과 사용자 경험을 모두 고려한 접근 방식이 필요합니다.

 

 

1. 

예를 들어, 아마존의 배송 옵션에서는 표준 배송이나 특급 배송을 선택하는 단순한 질문과 함께 추가적인 설정으로 배송 시간을 선택할 수 있습니다. 그러나 고객은 배송 방법(트럭, 비행기, 배 등)이나 구체적인 경로 등에 대해 걱정할 필요가 없습니다. 이는 서비스가 중요한 선택사항에 초점을 맞추고, 불필요한 세부사항은 숨김으로써 사용자 경험을 단순화한다는 것을 보여줍니다.

 

아마존과 고객 간의 계약은 고객이 배송 유형을 선택하고 주소를 확인하는 것에 기반합니다. 아마존은 약속된 목적지와 시간에 패키지를 배달할 책임이 있습니다. 고객은 배송 방법에 대해 걱정할 필요가 없으며, 아마존은 고객이 제공한 정보가 정확하다고 가정합니다. 이는 서비스가 사용자의 필요에 맞춰 구성되어야 함을 보여줍니다.

 

서비스 제공자가 전문가인 영역에서 추상화를 생성하여 다른 사람들이 쉽게 이용할 수 있도록 해야 한다고 설명합니다. 예를 들어, 어떤 사용자가 쿠버네티스에서 실행되는 애플리케이션의 인스턴스를 생성한다면, 해당 서비스의 역할은 사용자가 만든 추상화 인스턴스로부터 하위 수준의 리소스를 생성하는 것입니다. 이는 애플리케이션, 데이터베이스, 클러스터 등 다양한 서비스에 적용될 수 있습니다.

 

이 부분에서는 서비스 제공자가 사용자의 필요에 맞춰 설계된 서비스나 추상화를 통해 하위 수준의 리소스를 생성하고 관리하는 방법을 설명합니다. 이러한 방식으로 서비스를 구축하면 소프트웨어 개발 생명주기(SDLC)의 첫 번째 문제가 해결됩니다. 또한, 각자의 역할에 따라 단위 테스트를 수행하는 것이 쉬워집니다. 예를 들어, 서비스 제공자로서 제공하는 서비스가 올바르게 작동하는 것을 보장하는 것이 내 역할이 됩니다.

 

이 부분에서는 서비스 제공자가 자신이 제공하는 서비스가 예상대로 작동하는지 테스트하는 역할에 대해 설명합니다. 예를 들어 AWS의 경우, EC2 인스턴스 뒤의 하이퍼바이저가 예상대로 작동하는지 확인합니다. 그러나 EC2 인스턴스의 크기 선택 같은 사용자의 구체적인 요구사항은 그들의 책임이 아닙니다. 그들의 역할은 허용된 모든 인스턴스 유형이 생성되고 예상대로 작동하는 것을 보장하는 것입니다. 반면에, 사용자로서 내 역할은 내가 선택한 사양이 내 요구에 맞는지를 확인하는 것입니다.

 
 

단위 테스트와 그 결과를 정의하고 관찰하는 것이 추상화의 범위에 제한되기 때문에 쉽다고 설명합니다. 이러한 정보는 Backstage와 같은 UI에 전송되어야 하며, 서비스 제공자가 관리하는 부분은 이미 사용하는 도구들에 의해 커버되고 있습니다. 결과적으로, UI의 범위는 축소되며, 모든 것을 한 곳에서 관리하는 '하나의 창'으로 사용하는 것은 시간 낭비가 될 수 있습니다. 이미 각자가 익숙한 도구들을 사용하고 있기 때문입니다.

 

UI가 각 전문 분야에 맞춰진 특정 도구가 아니라, 전문 지식이 없는 사람들을 위한 단일 창으로 변모하고 있음을 설명합니다. 예를 들어, 데이터베이스 관리자에게는 특정 데이터베이스 서버를 관리하는 데 도움이 되는 도구들이 있습니다. 새로운 UI는 사용자들에게 그들이 직접적으로 관심을 가질 정보의 일부만을 제공함으로써 가시성을 제공합니다. 이는 아마존 배송 예시로 돌아가 보면, 고객이 배송에 대해 관심을 가지는 부분만을 보여주는 것과 유사합니다.

 

이 부분에서는 아마존 배송 추적을 예로 들어, 고객이 필요로 하는 정보를 제공하는 방식을 설명합니다. 고객은 패키지가 배송되었는지, 현재 위치가 어디인지만 확인할 수 있습니다. 이는 아마존이 가진 데이터의 일부에 불과합니다. 배송 업체는 패키지의 QR 코드, 운송 방법, 트럭 운전사 등 더 많은 정보를 볼 수 있습니다. 보안 분야에서는 전통적으로 보안 전문가가 애플리케이션 개발자에게 위협 요소를 해결하도록 위임하는 방식이 있었으나, 이는 종종 효과적이지 않았습니다.

 
 

많은 보안 문제는 운영 체제나 기본 이미지의 업그레이드, 운영 체제 라이브러리의 변경 등으로 해결될 수 있습니다. 그러나 개발자가 선택하지 않았거나 무작위로 선택한 요소를 수정하는 것은 비현실적입니다. 그러나 서비스를 제공하고 이를 애플리케이션 개발자들이 소비하는 방향으로 나아가면, 누가 어떤 보안 위협을 해결해야 하는지 명확한 구분이 생깁니다.

 
 
보안 책임의 분리에 대해 설명합니다. 개발자가 직접 코드에 포함한 라이브러리로 인해 발생한 보안 취약점은 개발자가 수정해야 합니다. 반면, 다른 사람이 제공한 서비스를 사용하여 발생한 문제는 그 서비스 제공자가 책임져야 합니다. 예를 들어, 데이터베이스 관리자가 서비스로 데이터베이스를 생성했고, 개발자가 그 인스턴스를 실행하는 경우, 발생하는 문제는 관리자의 책임이 될 수 있습니다. 이러한 구분은 보안 문제 해결에 있어 중요한 역할을 합니다.
 
 
 

이 부분에서는 서비스 사용자가 서비스 제공자의 책임 하에 있는 취약점이 있는 데이터베이스 인스턴스를 생성했을 수 있는 상황을 설명합니다. 예를 들어, 이미 알려진 취약점이 있는 PostgreSQL 13 데이터베이스를 사용하는 경우, 데이터베이스 관리자는 그러한 선택을 방지하기 위한 정책을 설정했어야 하며, 대신 안전한 버전(예: PostgreSQL 14)을 사용하도록 권장했어야 합니다. 서비스 제공자는 사용자가 잘못된 선택을 하지 않도록 지원하는 정책을 마련해야 합니다.

 
 
서비스 제공자는 서비스 사용으로 생성된 리소스가 안전하도록 보장하는 책임이 있으며, 서비스 사용자는 제공된 추상화 범위 내에서 안전한 선택을 해야 합니다. 서비스 제공자는 서비스 인스턴스에서 생성된 하위 수준 리소스를 스캔해야 하며, 서비스 사용자는 인스턴스 자체를 스캔해야 합니다.
 
 
사용자는 API 호출이 정확하고 요청된 정보가 원하는 상태와 일치하는지 확인해야 합니다. API 호출 이후의 과정, 즉 컨트롤 플레인 내에서 발생하는 모든 일은 서비스 제공자의 책임으로, 서비스가 제대로 작동하는지 보장하기 위해 테스트해야 합니다. 또한, 관찰 가능성은 서비스 제공자와 사용자가 사용하는 데이터 및 도구 사이의 가장 큰 차이점 중 하나일 수 있습니다.
 
 

이 부분에서는 서비스의 추상화에 포함되지 않는 정보를 최종 사용자에게 노출하는 것은 무의미하다고 설명합니다. 예를 들어, 사용자가 데이터베이스에 할당할 메모리 양을 지정할 수 있다면, 해당 메모리 정보는 최종 사용자에게 제공되는 관찰 가능성 도구의 그래프 중 하나로 제공되어야 합니다. 반면, 메모리 사양이 추상화의 일부가 아니라면, 서비스 자체에서 필요한 만큼의 메모리를 할당하는 것으로 간주하고, 이 정보를 최종 사용자의 관찰 가능성에 추가하는 것은 혼란을 증가시킬 수 있습니다.

 
 
 

이 부분에서는 내부 개발자 플랫폼(IDP)을 구축하는 것이 어렵다고 설명합니다. 단순히 기존 도구와 프로세스 위에 UI를 구축하는 것만으로는 충분하지 않으며, IDP는 핵심 역량을 벗어난 작업을 수행할 수 있도록 최종 사용자를 지원하는 서비스의 집합입니다. IDP는 단일 팀이 아닌, 여러 팀의 협력을 통해 구축되어야 하며, 이는 각 사용자의 필요에 부합하는 서비스를 제공하는 데 중점을 둡니다.

 
 
 

이 부분에서는 내부 개발자 플랫폼(IDP)을 효과적으로 구축하기 위한 전략에 대해 설명합니다. 데이터베이스, 인프라, 애플리케이션 아키텍처 등 특정 분야의 전문가들이 IDP를 구성하는 서비스를 구축합니다. 각 팀이 자동화를 통해 자급자족하고 독립적으로 작동하려면, 그들이 필요한 것을 정의하고 애플리케이션 및 기반 인프라의 상태를 관찰할 수 있어야 합니다. 단순한 자동화만으로는 이러한 목표를 달성할 수 없습니다.

 
 
 

OpenFunction은 자체 서버리스 컴퓨팅 플랫폼으로 쿠버네티스 기반이다.

서버리스란 개발자들이 애플리케이션을 만들 때 서버를 직접 구축하고 관리하는 대신에 클라우드 공급자(예: AWS, Azure, Google Cloud)가 제공하는 서버리스 서비스를 사용하는 것을 의미합니다. 이는 개발자들이 애플리케이션 코드에 집중할 수 있도록 도와주며, 서버 관리와 같은 인프라 작업을 간소화합니다.

그러나 이 방법을 선택하면 약간의 제한사항이 발생할 수 있습니다. 예를 들어, 클라우드 공급자가 제공하는 서비스의 방식과 기능을 따라야 하기 때문에 개발자가 특정한 제한 사항을 갖게 될 수 있습니다. 이것이 바로 "벤더 락인" 또는 "공급자 종속성"이라고 불리는 현상입니다.

간단히 말해서, 서버리스를 사용하면 편리하고 빠른 개발이 가능하지만, 클라우드 공급자가 정한 규칙과 제한사항을 따라야 하므로 개발자가 자유롭게 원하는 대로 모든 것을 조절하는 것이 어려울 수 있습니다. 따라서 이러한 제한을 고려하여 개발 방향을 결정해야 합니다.

OpenFunction은 서버리스 컴퓨팅 플랫폼으로, 사용자가 애플리케이션의 비즈니스 로직에 집중할 수 있게 해주는 것을 목표로 합니다. 즉, 사용자는 기반 인프라나 운영 체제, 하드웨어 등에 대해 걱정할 필요 없이 애플리케이션 개발에만 집중할 수 있습니다.

그러나 실제로 OpenFunction을 사용하려면, 사용자가 스스로 이 플랫폼을 설정하고 유지 관리해야 합니다. 이것은 Kubernetes 클러스터의 설정 및 유지 관리, OpenFunction이 통합하는 다양한 구성 요소(예: 빌드 도구, 실행 환경)의 유지 관리, 그리고 OpenFunction 자체의 유지 관리를 포함합니다.

간단히 말해서, OpenFunction은 개발자가 애플리케이션 개발에만 집중할 수 있게 도와주는 플랫폼이지만, 이 플랫폼 자체를 운영하고 유지 관리하기 위해서는 기술적인 지식과 추가적인 노력이 필요하다는 것입니다. 따라서 비전공자나 기술적 지식이 부족한 사람이 OpenFunction을 효과적으로 사용하려면, 기술적인 부분을 관리할 수 있는 전문가의 도움이 필요할 수 있습니다.

강점으로는 서버리스 컴퓨팅의 이점, 다양한 도구와의 통합

단점으로는 불친절한 문서화, 특정 기술에 대한 깊은 이해가 필요하다는 점, 빌더가 자주 유지되지 않는다는 점

실제 사용 사례: 함수 생성, HTTP 트리거, 데이터베이스 연동, 스케일링 테스트 등을 포함합니다.

 

로컬 소스 코드에서 함수를 빌드 방법

컨테이너 이미지로 소스 코드 패키징: 로컬에 있는 소스 코드를 컨테이너 이미지로 패키징하고, 이 이미지를 컨테이너 레지스트리에 푸시합니다.

Dockerfile 사용: 소스 코드가 'samples' 디렉토리에 있다고 가정할 때, 아래와 같은 Dockerfile을 사용하여 소스 코드 번들 이미지를 빌드할 수 있습니다

dockerfileCopy code
FROM scratch
WORKDIR /
COPY samples samples/

 

이미지 빌드 및 푸시: 다음 명령어를 사용하여 소스 코드 번들 이미지를 빌드하고 푸시합니다.

bashCopy code
docker build -t <your registry name>/sample-source-code:latest -f </path/to/the/dockerfile> .
docker push <your registry name>/sample-source-code:latest

 

 

Scratch 이미지 사용 권장: 소스 코드 번들 이미지를 빌드할 때는 비어 있는 scratch 이미지를 기본 이미지로 사용하는 것이 좋습니다. 비어 있지 않은 기본 이미지는 소스 코드 복사에 실패할 수 있습니다.

 

Function 정의 변경: Git 저장소 방식으로 **spec.build.srcRepo.url**을 정의하는 것과 달리, 로컬 소스 코드를 사용할 때는 spec.build.srcRepo.bundleContainer.image 필드를 정의해야 합니다.

yamlCopy code
apiVersion: core.openfunction.io/v1beta2
kind: Function
metadata:
  name: logs-async-handler
spec:
  build:
    srcRepo:
      bundleContainer:
        image: openfunctiondev/sample-source-code:latest
      sourceSubPath: "/samples/functions/async/logs-handler-function/"

 

Cloud Native Buildpacks 사용: OpenFunction은 Cloud Native Buildpacks를 사용하여 Dockerfile 생성 없이 함수 이미지를 빌드하는 것을 지원합니다. 이는 Serverless Applications을 Dockerfile과 함께 빌드할 때도 사용될 수 있습니다​​.

 

Build 섹션 정의를 통한 함수 빌드: 사용자는 Git 저장소의 소스 코드나 로컬에 저장된 소스 코드에서 함수나 애플리케이션을 빌드할 수 있습니다. Function 정의에 빌드 섹션을 추가하면, 서빙 섹션도 정의되어 있다면 빌드가 완료되자마자 함수가 시작됩니다​​.

 

Pack CLI 사용: 디버그 목적이나 오프라인 환경에서는 로컬 소스 코드에서 직접 함수 이미지를 빌드하는 것이 필요할 수 있습니다. 이를 위해 Pack CLI를 사용할 수 있습니다. Pack는 Cloud Native Buildpacks 프로젝트에 의해 유지되며 빌드팩을 사용하여 애플리케이션을 빌드하는 기능을 제공합니다​​.

 

OpenFunction Builders: Cloud Native Buildpacks를 사용하여 함수 이미지를 빌드하려면 빌더 이미지가 필요합니다. OpenFunction 커뮤니티에서는 여러 인기 언어에 대한 빌더를 제공하고 있습니다​​.

git 리포지토리의 소스 코드에서 함수 빌드하기

아래와 같이 함수 정의에 빌드 섹션을 추가하기만 하면 함수 이미지를 빌드할 수 있습니다. 서빙 섹션이 함께 정의되어 있으면 빌드가 완료되는 즉시 함수가 실행됩니다.

apiVersion: core.openfunction.io/v1beta2
kind: Function
metadata:
  name: logs-async-handler
spec:
  version: "v2.0.0"
  image: openfunctiondev/logs-async-handler:v1
  imageCredentials:
    name: push-secret
  build:
    builder: openfunction/builder-go:latest
    env:
      FUNC_NAME: "LogsHandler"
      FUNC_CLEAR_SOURCE: "true"
      ## Customize functions framework version, valid for functions-framework-go for now
      ## Usually you needn't to do so because the builder will ship with the latest functions-framework
      # FUNC_FRAMEWORK_VERSION: "v0.4.0"
      ## Use FUNC_GOPROXY to set the goproxy
      # FUNC_GOPROXY: "https://goproxy.cn"
    srcRepo:
      url: "https://github.com/OpenFunction/samples.git"
      sourceSubPath: "functions/async/logs-handler-function/"
      revision: "main"

 

 

 

이외에도 아래와 같은 방법으로 빌드가 가능하다.

  1. Pack CLI 사용: 디버그 목적이나 오프라인 환경에서는 로컬 소스 코드에서 직접 함수 이미지를 빌드하는 것이 필요할 수 있습니다. 이를 위해 Pack CLI를 사용할 수 있습니다. Pack는 Cloud Native Buildpacks 프로젝트에 의해 유지되며 빌드팩을 사용하여 애플리케이션을 빌드하는 기능을 제공합니다​​.
  2. OpenFunction Builders: Cloud Native Buildpacks를 사용하여 함수 이미지를 빌드하려면 빌더 이미지가 필요합니다. OpenFunction 커뮤니티에서는 여러 인기 언어에 대한 빌더를 제공하고 있습니다​​.

 

 

 

-참고 URL

https://openfunction.dev/docs/introduction/

[Introduction

Overview OpenFunction is a cloud-native open source FaaS (Function as a Service) platform aiming to let you focus on your business logic without having to maintain the underlying runtime environment and infrastructure. You can generate event-driven and dyn

openfunction.dev](https://openfunction.dev/docs/introduction/)

'job > devops' 카테고리의 다른 글

istio-2  (1) 2025.04.17
istio-1  (0) 2025.04.08
taskfile  (0) 2024.03.10
kubewarden  (0) 2024.01.20
git common flow(또는 gitlab flow) 브랜치 전략에 대한 설명  (0) 2023.06.13

테라폼 스터디 대망의 마지막(6)주차이다.

 

6주차 주제는 TFC

TFC란 프로비저닝 대상과 별개로 state를 관리할 수 있도록 SaaS 형태로 하시코프에서 제공해준다.

몇몇 기능은 유료지만 주 목적인 state 관리는 무료.

 

참고로 스터디에서는 GitHub을 사용하지만 나는 GitLab으로 진행

 

우선 다음 저장소 포크 : https://github.com/terraform101/terraform-aws-tfc-workflow

 

GitHub - terraform101/terraform-aws-tfc-workflow: [Chapter 8] CICD - TFC Workflow

[Chapter 8] CICD - TFC Workflow. Contribute to terraform101/terraform-aws-tfc-workflow development by creating an account on GitHub.

github.com

 

리드미 생성 안되도록 하고

빈 프로젝트 생성

Push an existing folder 설명 대로 순서대로 진행하여

디렉토리 포크 완료

main.tf에 조직 이름 수정해주고

커밋 완료

terraform-aws-tfc-workflow 워크스페이스가 생성된것이 확인된다.

plan 에러가 발생한다.

prefix 변수를 추가해준다.

또다시 에러가 난다.

다시보니 오타가..ㅎㅎ

오타 수정해주고 다시 돌려보면

 

위와같이 에러는 나지만... AWS 관련 설정이 없다는 에러가 나온다. 즉 prefix는 정상적으로 설정됐다는것.

마지막으로 키 넣어주고 다시 플랜을 해보면

정상적으로 동작한다.

 

위와같이 tfc 페이지에서도 확인이 가능하다.

apply 실행하면 실시간으로 확인 가능

state 파일이 없다.

 

앞서 말한것처럼 state 파일은 tfc가 관리.

 

 

GitLab과 tfc를 연동해보자.

위와같이 VCS 프로바이더를 깃랩으로 설정해주면 입력해야하는 정보들이 확인된다.

 

유저 설정중 어플리케이션 클릭하고

리다이렉트 URI 입력후 생성하면

다음과같이 어플리케이션 아이디와 시크릿 정보 확인이 가능하다.

위와같이 연결해주면

자동으로 로그인창 출력

인증해주면

성공

다시 버전컨트롤 워크플로우에서 레파지토리 선택하기위해 들어가서 조금 기다리면

계정으로 로그인 가능한 프로젝트리스트가 확인된다.

 

테스트로 생성한 워크플로우 프로젝트 검색해서 선택해주면

위와같이 몇몇 설정이 나오는데 오토 어플라이 선택한다.

 

이외에도 브랜치명 입력해주고 트리거 런 선택. Pull 리퀘스트(깃랩에선 머지리퀘스트) 오토매틱 체크해주고..하단의 업데이트 클릭

이렇게 하면 워크스페이스와 VCS간 최초 연동되면 마지막 커밋 내용을 기반으로 Run이 실행

 

마지막으로 연동테스트를 위해

main.tf에 terraform cloud 항목 모두 주석처리하고

새로운 브렌치 생성한다음

파일 수정이 안돼서 다시 진행

위와같이 MR(PR)을 생성하여 병합을 해보자.

머지하면

tfc에서 동작하는것을 확인할수있다 ! (비록실패했찌만 ㅎㅎ) 어쨌든 연동된것을 확인할수있다~!

5주차 테라폼 주제 : 프로비저닝 파이프라인이다.

 

스터디에서는 github action을 이용하였는데 블로그 작성은 gitlab CI를 이용해서 실습을 진행해볼것이다. 

 

추가로 파이프라인 작성을 도와주는 plumber라는 도구를 이용해볼것이다. 아직 클로즈베타라 계정 신청해서 사용이 가능하다. 여러 개발언어에 대한 파이프라인을 제공해줘서 나름 쓸만할것같다.

 

terraform + gitlab CI 를 이용해서 EC2를 생성하는 파이프라인을 만들어보기.

plumber 화면
이렇게 파이프라인을 제공해준다.

 

다음과같이 새로운 프로젝트를 생성해주고..

plumber에서 알려주는 gitlab CI 동작에 필요한 변수들을 등록해준다. 

위와같이 gitlab 페이지에서 프로젝트 변수(또는 그룹변수)를 등록해줘도 되고.

위와같이 파이프라인내에 직접 변수를 등록해줘도 된다. 나는 테스트용이기 때문에 후자로 선택했다. 하지만 협업환경이여서 여러 사람들이 여러 파이프라인을 관리해야한다면 동일하게 사용될 변수들이 있을것이다. 이럴때는 gitlab에서 그룹변수를 지정하는것이 좋을것이다.

 

프로젝트에 소스 Push.

 

위와같이 .gitlab-ci.yml을 작성하여 파이프라인을 작성해준다.

gitlab 파이프라인을 rules나 only 를 통해서 if문을 줘서 파이프라인을 동작시킬수있다. 브랜치별로 동작되는 스테이지를 다르게하는등의 효과를 가질수잇다.

 

파이프라인이 실행되고 위와같이 정상적으로 terraform으로 어플라이가 실행됐다. 테스트이기 때문에 바로 destroy도 해주었다.

테라폼 init이 정상적으로 파이프라인에서 동작된것이 확인된다.

SAST도 잘 실행됐다.

 

terraform plan도 정상적으로 실행됐다.

 

위와같이 terraform apply도 정상적으로 동작돼서 AWS 리소스도 정상적으로 생성됐음이 확인된다.

 

위와같이 파이프라인에 대한 결과들(각종 테스트 결과와 있다면 도커 이미지등)이 아티팩트로 생성되는것을 확인할수있다. 

 

만약 여러 사람들과 협업하면서 코드를 리뷰하고 승인을 받는 절차가 필요하다면 4주차때 작성한것처럼 리뷰/승인 절차를 gitlab 파이프라인에 추가해주는것도 좋은 협업환경이 될것이다.

 

 

1. State 란

책과 책갈피 예시:
책은 여러 페이지로 구성되어 있으며, 각 페이지에는 다양한 내용이 담겨 있습니다.
책갈피는 책을 읽다가 멈춘 특정 페이지를 표시하여, 다음에 책을 읽을 때 어디서부터 시작해야 하는지를 알려줍니다.
Terraform과 State 예시:
Terraform은 여러 리소스(서버, 데이터베이스 등)로 구성되어 있으며, 각 리소스에는 다양한 설정이 담겨 있습니다.
State는 Terraform으로 인프라를 구성하다가 현재 어떤 리소스가 어떤 상태인지를 저장하여, 다음에 인프라를 변경할 때 어떤 리소스를 어떻게 변경해야 하는지를 알려줍니다.
상세 설명:
책갈피 없이 책 읽기:
책갈피가 없다면, 매번 책을 읽을 때마다 어디까지 읽었는지를 기억하거나 찾아야 합니다.
State 없이 Terraform 사용하기:
State가 없다면, Terraform은 매번 인프라의 현재 상태를 알 수 없어서, 어떤 리소스를 생성, 수정, 삭제해야 하는지를 판단하기 어렵습니다.

 

 

Serial을 기준으로 State Backup을 관리한다.

위와 같이 테라폼 내용을 수정/배포하면 Serial이 변경되는것을 확인할 수 있다.

 

팀 단위로 테라폼을 운영할때는 팀 모두가 동일한 state를 이용해야 하기 때문에 공유 위치에 state파일을 저장해야한다.

 

워크스페이스를 분리하여 운영할수도 있다.

개발, 테스트, 스테이징, 운영등의 환경을 워크스페이스로 분리하면 리스크를 관리하고 리소스를 최적화, 개발 효율성도 높일수 있을것이다. 또한 배포 관리도 가능할것이고.

위와같이 dev 라는 workspace에서는 Dev.txt 파일이 생성된것을 볼수있다.

 

그럼 다시 

prod workspace에서는 prod.txt 가 생성된것을 확인할 수 있다.

2. 모듈

모듈이란 재사용 가능한 코드블록으로 여러 리소스와 설정을 그룹화하여 관리가 가능하다. 코드의 재사용성과 관리효율성을 향상시킨다.

 

 

위와같이 모듈을 사용하여 사용자 아이디와 패스워드가 생성되는것을 볼수있다.

 

모듈에 사용할 프로바이더는 루트모듈에서 프로바이더를 정의한다.

 

 

테라폼 레지스트리를 통해 모듈을 다운받을수도 있다.

https://registry.terraform.io/

 

Terraform Registry

 

registry.terraform.io

 

 

위와 같이 AWS s3-bucket 모듈을 사용해볼것이다.

 

 

위와같이 모듈에의해 버킷이 생성된것을 확인할수있다.

 

얼른삭제해준다.

정삭적으로 삭제됐다.

 

 

테라폼은 결국 코드이기 때문에 버전 형상관리를 해줘야한다.

VCS 도구중 가장 대표적인 git, gitlab을 통한 형상관리가 가능하다.

다만 하나의 원격 저장소를 여러 개발자가 사용한다면 충돌이 발생한다. 그래서 항상 push 전에 Pull 을 해주는 방안도 있지만 매우 귀찮은 일이다.

이때 사용할수 있는게 git branch를 사용하는것이다. 

플로우는 이런식으로...

 

 

깃랩에서는 이렇게 여러개의 브랜치를 이용할수있고

머지 리퀘스트를 생성해서 병합요청을 진행한다.

병합 진행하기전 코드에 문제가 없는지 리뷰를 진행해줄 리뷰어도 지정하고...

 

리뷰가 완료되면 최종적으로 병합을 진행한다. 

 

이때 approval을 지정하여 단계별 승인자도 지정해줄수있다.

1. Android OS

 

2. iOS

+ Recent posts