본문 바로가기

엔지니어/Kubernetes

CI / CD 구성

728x90
반응형

Kubernetes cluster 를 구성하고 CI/CD를 구성하여 테스트

 

1. CI/CD 구성을 위한 Kubernetes 구성

 

위 테스트 환경

OS : rhel8.x

Container : cri-o

CNI : calico

STORAGE : ceph

hosts 파일에 도메인을 지정하여 테스트(dns X)

metal lb 통해서 ip할당받은 nginx ingress로 도메인 설정

 

 

처음 마스터1 워커2로 진행하다가 워커1대를 더 추가하였다.

 

로직

개발자는 k8s 내 gitlab에 소스를 메인 브랜치로 퍼밋(트리거)하면  gitlab runner 가 동작하고 kaniko 를 생성하고 kaniko는 repo에 있는 dockerfile을 통하여 이미지를 생성하고 harbor에 이미지를 저장한다. 이때 harbor는 image scan 을 한다.

kaniko 는 생성된 이미지의 태그를 alpine-git 을 생성하여 manifest repo에 태그를 수정해주고 manifest repo 가 수정됨에 따라 argo cd에서 chart를 인지하여 변경된 태그의 이미지를 harbor에서 불러와 배포하게 된다.

 

테스트는 간단한 node js로 진행했다.

 

 

 

kub 설치
 cat << /etc/hosts
    6  [master의 IP] k8s-master-1
    7  [node1의 IP] k8s-worker-1
    8  [node2의 IP] k8s-worker-2


systemctl stop firewalld
systemctl disable firewalld

hostnamectl set-hostname k8s-master-1
vi /etc/selinux/config

sudo swapoff -a
 vi /etc/fstab  #swap 주석

sudo dnf install -y iproute-tc

cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF

sudo modprobe overlay
sudo modprobe br_netfilter

# sysctl params required by setup, params persist across reboots
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables  = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward                 = 1
EOF

# Apply sysctl params without reboot
sudo sysctl --system



subscription-manager register #인증
louie0 / T

yum update -y

## cri-o 설치
export VERSION=1.26
sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_8/devel:kubic:libcontainers:stable.repo
sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable:cri-o:$VERSION.repo https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable:cri-o:$VERSION/CentOS_8/devel:kubic:libcontainers:stable:cri-o:$VERSION.repo
sudo dnf install cri-o -y
sudo systemctl enable crio
sudo systemctl start crio

## kubelet, kubeadm, kubectl 설치
sudo vi /etc/yum.repos.d/kubernetes.repo
---
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
exclude=kubelet kubeadm kubectl
---

sudo dnf install -y kubelet-1.26.1 kubeadm-1.26.1 kubectl-1.26.1 --disableexcludes=kubernetes
sudo systemctl enable kubelet
sudo systemctl start kubelet
systemctl status kubelet

yum install podman -y

## worker 노드는 조인 (worker node는 여기까지하면 됨)
kubeadm join 10.11.5.160:6443 --token flrb01.mtd7t9p9p6crpoe0         --discovery-token-ca-cert-hash sha256:265f34008c63212ba046fc52346428a8979719b5a5ad0012da0059aeb0d123b5
kubectl get nodes -o wide

##master 노드 토큰생성 (24시간 뒤 초기화)
kubeadm token create
kubeadm token list
##master 노드 해쉬값 조회
openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'

kubeadm join 10.11.5.160:6443 --token 56cpd3.0a94cmcxjhdvm5ma --discovery-token-ca-cert-hash sha256:265f34008c63212ba046fc52346428a8979719b5a5ad0012da0059aeb0d123b5


### 로그 "Failed to get system container stats" err="failed to get cgroup stats for  오류
mkdir -p  /etc/systemd/system/kubelet.service.d
vi /etc/systemd/system/kubelet.service.d/11-cgroups.conf
----
Environment="KUBELET_CGROUP_ARGS=--cgroup-driver=cgroupfs --runtime-cgroups=/systemd/system.slice --kubelet-cgroups=/systemd/system.slice"

[Service]

CPUAccounting=true

MemoryAccounting=true
----

systemctl daemon-reload
systemctl restart kubelet

kubectl top nodes



## worker node 에서 kubectl get nodes 조회시 couldn't get current server API group list 오류 해결
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/kubelet.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
## 쿠버네티스 컨피그 파일이 $home/.kube 디렉토리 아래 없어서 현재 유저정보가 컨피그파일에 반영이 안됨

## 아래는 master 노드로 설정

## calico & csi 드라이버설치
curl -L https://github.com/projectcalico/calico/releases/download/v3.24.5/calicoctl-linux-amd64 -o calicoctl
chmod 700 calicoctl
sudo mv calicoctl /usr/bin/
calicoctl node status
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.25.1/manifests/csi-driver.yaml
kubectl get pods -n calico-system

##istio 설치
curl -sL https://istio.io/downloadIstioctl | sh -
sudo cp ~/.istioctl/bin/istioctl /usr/local/bin
./istioctl install --set profile=demo --set components.cni.enabled=true -y

kubectl apply -n istio-system -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: kiali-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 8080
      name: http
      protocol: HTTP
    hosts:
    - "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: kiali
spec:
  hosts:
  - "*"
  gateways:
  - kiali-gateway
  http:
  - match:
    - uri:
        prefix: /kiali
    route:
    - destination:
        port:
          number: 20001
        host: kiali
EOF






##Metallb 설치
kubectl get configmap kube-proxy -n kube-system -o yaml | grep strictARP
kubectl get configmap kube-proxy -n kube-system -o yaml | sed -e "s/strictARP: false/strictARP: true/" | kubectl apply -f - -n kube-system
kubectl get configmap kube-proxy -n kube-system -o yaml |  grep strictARP


kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.7/config/manifests/metallb-native.yaml
kubectl get -n metallb-system pods

vi l2-network.yaml
----------------------------------------------------------------------------------------
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
 name: first-pool
 namespace: metallb-system
spec:
 addresses:
 - 10.11.5.170-10.11.5.185

---

apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
 name: second-pool
 namespace: metallb-system
spec:
 addresses:
 - 10.11.5.190-10.11.5.200

---

apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
 name: l2-network
 namespace: metallb-system
spec:
 ipAddressPools:
 - first-pool
 - second-pool
------------------------------------------------------------------------------------------------------------------------------------
kubectl apply -n metallb-system -f l2-network.yaml



##Ceph 설치 (https://www.itmaya.co.kr/wboard/view.php?wb=tech&idx=35)

##Ceph 강제삭제 (https://rook.io/docs/rook/v1.11/Getting-Started/ceph-teardown/#removing-the-cluster-crd-finalizer)
for CRD in $(kubectl get crd -n rook-ceph | awk '/ceph.rook.io/ {print $1}'); do
    kubectl get -n rook-ceph "$CRD" -o name | \
    xargs -I {} kubectl patch -n rook-ceph {} --type merge -p '{"metadata":{"finalizers": []}}'
done

## Ceph 트러블슈팅
ceph dashboard 나 ceph health에서
HEALTH_WARN application not enabled on 1 pool(s)가 발생할 경우


ceph-mon에서
sudo ceph health


sudo ceph health detail
여기서 문제가 되는 pool을 확인한다
만약 풀이 images 라면


sudo ceph osd pool application enable images rgw


sudo ceph health
정상인거 확인






##gitlab 설치

helm repo add gitlab https://charts.gitlab.io/
helm repo update
helm search repo git

helm install gitlab gitlab/gitlab -f values.yaml -n gitlab-ee --set certmanager-issuer.email=xxx@xxx.com
helm delete gitlab -n gitlab-ee

##gitlab root password 확인
kubectl get secret -n gitlab-ee gitlab-gitlab-initial-root-password -o jsonpath="{.data.password}" | base64 -d ; echo

환경이 도메인을 dns에 등록하지않아 gitlab runner 설치가 좀 애먹었는데 config를 깜빡하고 적지않은거같은데

기억을 더듬자면 ssl 인증서 부분때문에 gitlab 과 연동부분이 오류가 났었다.

해결법은 아마도 .. 기억은 잘 안나지만 ssl false 거나 인증서를 runner에게 줬거나 심었거나 했던거같다..





## kubernetes metric server 설치 (kubectl top)
https://velog.io/@_zero_/%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A4-metrics-server-%EC%84%A4%EC%B9%98

kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

metrics-server 디플로이먼트 설정 수정
--metric-resolution=15s 밑에
"--kubelet-insecure-tls" 설정 추가

dnsPolicy: ClusterFirst 밑에
"hostNetwork: true" 설정 추가

kubectl top node
kubectl top pod

 

 

 

main repo

 

manifest repo

manifest repo 는 halm chart로 생성

 

tagging 을 해주는 스크립트

# tagging.sh
sed -i "s|tag: .*|tag: $CI_COMMIT_SHORT_SHA|" /helm-repo/helm-chart/values.yaml

 

values.yaml

----------------------------------

 

# Default values for test-chart.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.

replicaCount: 1

image:
  repository: harbor.xxx.com/gitlab-instance-acb80999/test
  pullPolicy: IfNotPresent
  # Overrides the image tag whose default is the chart appVersion.
  tag: 494e26b7
#  tag: 494e26b7

imagePullSecrets: 
  - name: harbor-crt
nameOverride: ""
fullnameOverride: ""

serviceAccount:
  # Specifies whether a service account should be created
  create: true
  # Annotations to add to the service account
  annotations: {}
  # The name of the service account to use.
  # If not set and create is true, a name is generated using the fullname template
  name: ""

podAnnotations: {}

podSecurityContext: {}
  # fsGroup: 2000

securityContext: {}
  # capabilities:
  #   drop:
  #   - ALL
  # readOnlyRootFilesystem: true
  # runAsNonRoot: true
  # runAsUser: 1000

service:
  type: ClusterIP
  port: 3000

ingress:
  enabled: true
  className: "nginx"
  annotations: 
    #kubernetes.io/ingress.class: nginx
    # kubernetes.io/tls-acme: "true"
    nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
  hosts:
    - host: cicdtest.xxx.com
      paths:
        - path: /
          pathType: ImplementationSpecific
  tls: 
    - secretName: xxx.com-ssl
      hosts:
        - cicdtest.xxx.com

resources: {}
  # We usually recommend not to specify default resources and to leave this as a conscious
  # choice for the user. This also increases chances charts run on environments with little
  # resources, such as Minikube. If you do want to specify resources, uncomment the following
  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
  # limits:
  #   cpu: 100m
  #   memory: 128Mi
  # requests:
  #   cpu: 100m
  #   memory: 128Mi

autoscaling:
  enabled: false
  minReplicas: 1
  maxReplicas: 100
  targetCPUUtilizationPercentage: 80
  # targetMemoryUtilizationPercentage: 80

nodeSelector: {}

tolerations: []

affinity: {}

 

----------------------------------

.gitlab-ci.yml 

 

stages:
  - build

build:
  stage: build
  image:
    # 구글 공식 kaniko 이미지 repository 사용
    # debug 태그 이미지를 사용해야 파이프라인 출력 내용 확인 가능
    name: gcr.io/kaniko-project/executor:debug
    # entrypoint를 override 하지 않으면 아래 script 커맨드들이 실행되지 않음
    entrypoint: [""]
  before_script:
  - mkdir -p /kaniko/.docker
  - echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json
  - |
    echo "-----BEGIN CERTIFICATE-----
    ##여기에 인증서 넣으면됨. 파일로 넣을라했는데 귀찮아서 kaniko 생성할때 인증서도 생성
    -----END CERTIFICATE-----" >> /kaniko/ssl/certs/additional-ca-cert-bundle.crt
  script:
    # registry 접속 정보를 저장하기 위한 디렉토리 생성
    - mkdir -p /kaniko/.docker
    # Gitlab > Repository > Setting > CI/CD > Variables 사용
    # variables에 저장해서 사용
    # HARBOR_URL : harbor.example.com
    # HARBOR_USER : username
    # HARBOR_PASSWORD : userpassword
    - echo "{\"auths\":{\"$HARBOR_URL\":{\"username\":\"$HARBOR_USER\",\"password\":\"$HARBOR_PASSWORD\"}}}" > /kaniko/.docker/config.json
    # Gitlab에 미리 정의된 Variables 사용
    # CI_PROJECT_DIR : Dockerfile을 포함한 Source Repositry 경로
    # CI_COMMIT_SHORT_SHA : Commit SHA의 앞 8자를 tag로 사용
    - /kaniko/executor --insecure --skip-tls-verify --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination $HARBOR_URL/$CI_PROJECT_PATH:$CI_COMMIT_SHORT_SHA

helm-value-update:
  stage: build
  image:
    name: alpine/git:latest
    entrypoint: [""]
  script:
    - mkdir /helm-repo; cd /helm-repo
    - git config --global http.sslVerify false
    - git config --global user.name "louie0"
    - git config --global user.email "louie0@xxx.com"
    - git clone https://root:Softwiz%4012@gitlab.xxx.com/gitlab-instance-acb80999/helm-chart.git
    # CI_COMMIT_SHORT_SHA 를 HELM values.yaml 파일 수정
    - echo $CI_COMMIT_SHORT_SHA
    - cd helm-chart; sh /helm-repo/helm-chart/tagging.sh
    - git add .; git commit -m "tagging"; git push
  only:
    - main

 

-----------------------------------

Dockerfile

# 베이스 이미지 설정
FROM node:16

# Node.js 앱을 위한 app 폴더 생성
RUN mkdir -p /app

# 어플리케이션 폴더를 WORKDIR명령어로 지정 - 서버 가동용
WORKDIR /app

# 가능한 package.json 과 package-lock.json을 모두 복사하기 위해서 와일드 카드 사용
COPY package*.json /app/

# 의존성 설치
RUN npm install

# 앱 소스코드 추가
COPY app.js /app/

# 앱이 3000번 포트에 바인딩 되어있기 때문에 컨테이너의 3000번 포트를 열어줌
EXPOSE 3000
# 인자값을 지정하지 않을시 node app.js를 실행
CMD [ "node", "app.js" ]

 

그냥 node.js 이미지 불러오는 dockerfile 임.

 

-----------------------------

app.js

 

var express = require('express');
var app = express();

app.get('/', (req, res)=>{
    res.send('<h1>hello Docker!</h1>')
});

app.listen(3000,'0.0.0.0',()=>{
    console.log('Server Start : port 3000');
});

 

그냥 hello docker! 나오는 페이지 설정임

 

 

 

 

 

app.js를 수정하고 main 브랜치로 commit을 하게되면

 

 

 

 

이미지 빌드와 tagging  파이프라인이 동작하고

 

 

 

manifest repo 에 tag와 같은 tag를 가진 이미지가 harbor에 생성되고

 

 

 

 

위와 같이 argo cd를 통해 자동으로 배포가 된다. 

 

 

추후 여러가지 배포(blue/green , canary)등 환경 구성하는것도 테스트 예정이다.

또한 egress 를 통해 외부연동되는부분도 테스트 예정이다.

 

반응형

'엔지니어 > Kubernetes' 카테고리의 다른 글

kubernetes 명령어 모음  (0) 2023.11.06
Harbor  (0) 2023.11.06
Helm  (0) 2023.11.06
Istio  (0) 2023.11.06
Calico CNI  (0) 2023.11.06