AKS에 thanos와 prometheus, grafana를 사용하여 모니터링 시스템을 구축하였습니다. 이 내용에서 추가적으로 cicd를 구축해보는 것이 이번 내용입니다. 이전글과 연동하셔도 상관 없으며 따로 구축하셔도 무방한 내용입니다. Azure CLI에 대한 코드도 적어두었습니다. 해당 코드는 vscode에서 powershell로 Azure cli를 사용하고 있습니다.
만약 이미 aks 리소스가 존재한다면 VM(ubuntu)만 한개 생성해주시면 됩니다.
가장 먼저 Azure cli를 사용하기 위하여 login을 합니다. 해당 ID에 여러개의 구독을 가지고 있거나 여러 테넌트에 등록된 계정이라면 구성을 원하는 구독을 세팅하는 작업이 필요합니다.
# use azure cli
az login
# default subscription check
az group list --output table
# subscription setting
az account set --subscription "Subscription ID"
구독이 설정 되었다면 이후에 jenkins용 vm과 aks를 생성합니다. 이전에 말씀드린 것과 같이 VScode에서 powershell로 azure-cli를 사용중입니다. 또한 아래 작업중에는 ACR 생성 및 ACR로 접근하기 위해 AKS 클러스터에 ACR Role을 할당하는 작업이 들어가 있습니다. 해당 내용은 #Generate acr과 #connect aks to acr (role) 부분이니 참고해주시기 바랍니다. 이 작업을 수행하지 않으면 image에 에러가 나오게 됩니다.
# Variable
$aksrg="rg-krc-dev-aks01"
$aksvnet01="vnet-krc-dev-aks01"
$akssnet01="snet-krc-dev-aks01"
$akscluster="aks-krc-dev-app01"
$aksnodepool="nokrcdaks01"
$aksnoderg="rg-krc-dev-node01"
$vmsnet01="snet-krc-dev-vm01"
$vmnsg01="nsg-krc-dev-vm01"
$vmpip01="pip01-krc-dev-jenkins01"
$vmnic01="nic01-krc-dev-jenkins01"
$vmosdisk="osdisk-krc-dev-jenkis01"
$vmname="vmkrcdevjenkins"
$vmusername="azureuser"
$vmpassword="Password1234"
# config resource group
az group list --output table
# create resource group, virtual network, subnet
az group create -n $aksrg --location koreacentral
az network vnet create -g $aksrg -n $aksvnet01 --subnet-name $akssnet01 --address-prefixes "10.0.0.0/16" --subnet-prefixes "10.0.0.0/24"
az network vnet subnet create -g $aksrg --vnet-name $aksvnet01 -n $vmsnet01 --address-prefixes "10.0.1.0/24"
# nsg create for vm
az network nsg create -g $aksrg -n $vmnsg01
az network nsg rule create -g $aksrg --nsg-name $vmnsg01 -n nsgsr-vm-ssh --destination-port-ranges 22 --access Allow --priority 100 --description "ssh"
az network nsg rule create -g $aksrg --nsg-name $vmnsg01 -n nsgsr-vm-http --destination-port-ranges 80 --access Allow --priority 200 --description "http"
az network nsg rule create -g $aksrg --nsg-name $vmnsg01 -n nsgsr-vm-jenkins --destination-port-ranges 8080 --access Allow --priority 300 --description "jenkins"
az network nsg rule create -g $aksrg --nsg-name $vmnsg01 -n nsgsr-vm-go --destination-port-ranges 9000 --access Allow --priority 400 --description "when i make my project, i use this port for golang"
# connect nsg to subnet
az network vnet subnet update -g $aksrg -n $vmsnet01 --vnet-name $aksvnet01 --network-security-group $vmnsg01
# create vm with pip
az network public-ip create --name $vmpip01 -g $aksrg --sku Standard
az network nic create -g $aksrg -n $vmnic01 --vnet-name $aksvnet01 --subnet $vmsnet01 --private-ip-address 10.0.1.4 --location koreacentral --public-ip-address $vmpip01
az vm create -g $aksrg --name $vmname --image UbuntuLTS --admin-username $vmusername --admin-password $vmpassword --size Standard_D2S_v5 --os-disk-name $vmosdisk --os-disk-size-gb 30 --os-disk-caching ReadWrite --storage-sku StandardSSD_LRS --nics $vmnic01
# Generate aks using azurecni
az aks create --resource-group $aksrg --name $akscluster --network-plugin azure --nodepool-name $aksnodepool --node-vm-size standard_d2s_v5 --node-count 1 --vnet-subnet-id $(az network vnet subnet list --resource-group $aksrg --vnet-name $aksvnet01 --query "[0].id" --output tsv) --node-resource-group $aksnoderg --docker-bridge-address 172.17.0.1/16 --dns-service-ip 10.2.0.10 --service-cidr 10.2.0.0/24 --generate-ssh-keys
# Generate acr
az acr create --name k8scicdacrtest01 -g $aksrg --sku Basic --admin-enabled true
# connect aks to acr (role)
az aks update -n $akscluster -g $aksrg --attach-acr $(az acr list --resource-group $aksrg --query "[0].id" --output tsv)
# connect cluster
az aks get-credentials --resource-group $aksrg --name $akscluster
# config connection
kubectl get nodes
jenkins용 vm를 생성하는 이유는 기존에 jenkins 내부에 플러그인들이 2024-02-29에 사라질 예정입니다. 이에 대안으로 Azure에서 Azure-cli 사용을 권장하고 있습니다. 자세한 내용은 링크를 확인해주세요
기본적으로 VM에서 jenkins의 서비스를 실행시키기 위해서는 다운로드 받아야 되는 것들이 존재합니다. 기본적인 요소들은 같지만 언어는 사용하는 사람에 따라 다르니 해당 부분은 직접 설치해주시기 바랍니다. 참고로 ubuntu 22.04버전을 사용중입니다.
jenkins 플러그인의 대체로 Azure-cli를 권장하므로 이를 다운로드 받아 사용해야 합니다.
sudo apt-get install ca-certificates curl apt-transport-https lsb-release gnupg -y
sudo mkdir -p /etc/apt/keyrings
curl -sLS https://packages.microsoft.com/keys/microsoft.asc |
gpg --dearmor |
sudo tee /etc/apt/keyrings/microsoft.gpg > /dev/null
sudo chmod go+r /etc/apt/keyrings/microsoft.gpg
AZ_REPO=$(lsb_release -cs)
echo "deb [arch=`dpkg --print-architecture` signed-by=/etc/apt/keyrings/microsoft.gpg] https://packages.microsoft.com/repos/azure-cli/ $AZ_REPO main" |
sudo tee /etc/apt/sources.list.d/azure-cli.list
sudo apt-get update
sudo apt-get install azure-cli -y
sudo apt install openjdk-11-jre -y
curl -fsSL https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key | sudo tee /usr/share/keyrings/jenkins-keyring.asc > /dev/null
echo 'deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] https://pkg.jenkins.io/debian-stable binary/' | sudo tee /etc/apt/sources.list.d/jenkins.list > /dev/null
sudo apt-get update && sudo apt-get install jenkins -y
sudo service jenkins restart
sudo systemctl status jenkins.service
sudo apt-get install apt-transport-https ca-certificates curl software-properties-common -y
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo apt-key fingerprint 0EBFCD88
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
sudo apt-get update
sudo apt-get install docker-ce -y
sudo systemctl status docker.service
쿠버네티스의 경우 kubectl을 사용하기 위해 필요합니다.
간단하게 설치가 가능합니다. 이때도 구독 확인 필수
az login
sudo az aks install-cli
az aks get-credentials --resource-group rg-krc-dev-aks01 --name aks-krc-dev-app01
ubuntu에서 Golang을 설치하는 과정입니다. 최신버전은 링크를 확인해주시기 바랍니다
wget https://go.dev/dl/go1.20.5.linux-amd64.tar.gz
sudo tar -xvf go1.20.5.linux-amd64.tar.gz -C /usr/local
# .profile 수정
vi ~/.profile
#마지막 부분에 추가
export GOROOT=/usr/local/go
export GOPATH=$HOME/go
export PATH=$GOPATH/bin:$GOROOT/bin:$PATH
# 환경 변수 적용
. ~/.profile
# 설치 확인
go version
-- go version go1.20.5 linux/amd64 과 같이 버전이 출력되면 완료
# test 용 ping pong
mkdir -p ~/go/main
cd ~/go/main
vi main.go
-- 아래 코드 입력 간단한 ping pong 예제
package main
import(
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("ping", func(c *gin.Context){
c.JSON(http.StatusOK, gin.H{
"message":"pong",
})
})
r.Run(":9000")
}
---
go mod init main.go
go mod tidy
go run main.go
공인ip주소:9000/ping으로 접근 후 아래 사진과 같이 나오면 완료
혹시 공인 ip 주소가 기억 나지 않는경우
curl ifconfig.me
.kube파일과 docker를 젠킨스로 소유자 및 소유 그룹 변경을 실시합니다.
sudo usermod -aG docker jenkins;
sudo usermod -aG docker azureuser;
sudo touch /var/lib/jenkins/jenkins.install.InstallUtil.lastExecVersion;
sudo service jenkins restart;
sudo cp -R ~/.kube /var/lib/jenkins/
sudo chmod 755 /var/lib/jenkins/
sudo chown -R jenkins:jenkins /var/lib/jenkins
공인ip:8080으로 접근하면 jenkins의 초기 화면이 나오는데 initialPassword를 통하여 진입합니다.
sudo cat /var/lib/jenkins/secrets/initialAdminPassword
Select plugins to install 클릭 후 github 선택, install
영겁의 시간을 기다립니다...
계정을 설정합니다.
freestyle로 프로젝트 생성
생성 이후 관리 -> system 에서 아래쪽에 Global properties가 존재합니다. 이 부분에 ACR의 주소를 등록시켜줍니다. acr의 주소는 "acr생성시작성된이름.azureacr.io"입니다.
만약 기억이 나지 않는다면 콘솔로 접근하여 확인하시거나
az acr list -g $aksrg 를 입력하여 확인하시기 바랍니다.
이후 jenkins의 자격증명을 위해 acr의 서비스 주체를 생성합니다.
az ad sp create-for-rbac
-- 입력시 아래와 같은 결과물이 나오는데 메모필수
{
"appId": "",
"displayName": "",
"password": "",
"tenant": ""
}
--
$ACR_ID=$(az acr show --resource-group $aksrg --name k8scicdacrtest01 --query "id" --output tsv)
az role assignment create --assignee "appId값 입력" --role Contributor --scope $ACR_ID
여기까지 진행하면 jenkins의 ACR 접근을 위한 RBAC이 생성됩니다.
이제 jenkins에 해당 id를 등록시킵니다.
관리 -> Credentials -> System -> Global credentials (unrestricted)로 들어가 새로운 자격증명을 생성합니다. 여기서 Username은 appId이며 Password는 서비스 주체의 password입니다. 이 내용은 위에서 메모한 내용을 기반으로 합니다. ID는 acr-credentials와 같이 적당히 적으시면 됩니다.
github로 이동하셔서 Personal access Token을 생성합니다.
생성하며 나온 내용 또한 jenkins에 등록시킵니다
등록 이후 github에서 webhook으로 등록시킵니다.
jenkins의 credencial까지 등록을 완료하였다면 이제 실제 작업을 구성할 차례입니다. 이전에 freestyle로 생성한 프로젝트에서 구성작업을 실시합니다. github 주소 및 등록된 credential을 적용합니다.
Build Steps을 추가합니다.
WEB_IMAGE_NAME="${ACR_SERVER}/ping:${BUILD_NUMBER}"
docker build -t $WEB_IMAGE_NAME ./ping
docker login ${ACR_SERVER} -u ${ACR_ID} -p ${ACR_PASSWORD}
docker push $WEB_IMAGE_NAME
# Update kubernetes deployment with new image.
WEB_IMAGE_NAME="${ACR_SERVER}/ping:${BUILD_NUMBER}"
kubectl set image deployment/ping ping=$WEB_IMAGE_NAME
-- 빌드 이전에 aks cluster에 deployment를 배포하여야 합니다.
필자는 deployment의 이름을 ping으로 설정하였기 때문에 build step에 deployment/ping의 이미지를 변경하는 것으로 설정을 해두었습니다. 이 부분은 각자에 맞게 설정하면 되겠습니다.
아래는 필자의 간단한 ping.yaml의 간단한 예제를 적어두었습니다. 이를 이용하여 이미지를 변경하는 형식으로 진행되는 cicd입니다.
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: ping
spec:
replicas: 4
selector:
matchLabels:
app: ping
template:
metadata:
labels:
app: ping
spec:
containers:
- name: ping
image: aak1009/pingpong:latest
ports:
- containerPort: 9000
resources:
requests:
memory: "64Mi"
cpu: "125m"
limits:
memory: "128Mi"
cpu: "250m"
---
apiVersion: v1
kind: Service
metadata:
name: ping
spec:
type: LoadBalancer
ports:
- port: 9000
selector:
app: ping
k8s에서는 Pod 교체 전략을 변경할 수 있습니다. 여기서 교체전략은 Rolling Update와 Recreate 2개의 값이 존재하며 RollingUpdate는 Pod를 하나씩 죽이고 새로 띄우면서 순차적으로 교체하는 방식이고 Recreate는 기존 파드를 모두 삭제한 이후 새로운 파드를 생성하는 방식입니다. k8s deployment의 기본 속성은 RollingUpdate이므로 따로 명시하지 않았습니다.
만약 이를 명시한다면 아래와 같은 yaml파일과 같이 지정하면 됩니다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: ping
spec:
replicas: 4
strategy:
type: RollingUpdate
rollingUpdate:
maxUnvailable: 2
maxSurge: 4
... 이하생략
여기서 maxUnvailable은 롤링 업데이트 시 동시에 삭제할 수 있는 파드의 최대 개수를 의미하고, maxSurge 는 동시에 생성될 수 있는 파드의 최대 값을 의미합니다. (기본 25%)
빠르게 업데이트 하는 것도 중요하지만 이후에 벌어질 이펙트를 대비하여 적절한 값을 주는 것이 중요합니다. 이제 이 yaml파일을 이용하여 pod와 svc를 배포하고 빌드를 하시면 됩니다.
젠킨스로 이동하여 지금 빌드를 누르면 해당 파일을 빌드할 수 있습니다.
빌드를 실행시키게 되면 Build History가 생기면서 성공과 실패를 확인 할 수 있습니다.
값이 잘 변경됨을 확인 할 수 있었습니다.
이전에 webhook을 등록시켰다면 로컬에서 git으로 main브런치를 이용하여 push하게 되면 github에서 webhook으로 젠킨스에게 해당 내용을 보내게 되고 자동으로 빌드를 하게됨을 볼 수 있습니다.
물론 git의 브랜치를 변경하여 테스트를 진행해도 빌드 진행으로 이어지지 않는 것을 확인할 수 있습니다. git의 브랜치에 대한 명령어는 다음과 같습니다.
브랜치 생성
git branch 이름
브랜치 확인
git branch
브랜치 변경
git checkout 브랜치이름
URL에 get 요청으로 Rollingupdate를 볼 수도 있습니다.
마지막으로 해당 내용의 과정을 설명하면 깃헙으로 push -> github에서 웹 훅을 젠킨스에게 전달 -> 젠킨스에서 브랜치 확인 및 빌드시작(도커 이미지를 acr에 저장후 aks의 이미지 변경)
지금까지 사용한 모든 리소스를 삭제하며 마무리합시다.
az group delete -g "그룹이름"