-
Github 계정 (or Azure DevOps 계정)
-
Azure 계정 및 구독
-
Azure Cli 2.3 이상
-
IDE (VS Code, IntelliJ .. )
-
OSX, WSL, Linux
-
bash 설정
alias k='kubectl' alias ns='kubectl config set-context $(kubectl config current-context) --namespace' alias nsv='kubectl config view | grep namespace:'
- 본 프로젝트의 목표는 마이크로서비스로 구성된 Spring Petclinic 앱을 배포하기 위해 Non-prod 클러스터 환경을 구성하는 것임.
- Non-prod 환경은 개발계과 스테이지계로 구성되어 있으며 개발계는 Kubernetes Object를 최대한 활용하고 스테이지계는 Azure PaaS를 최대한 활용함.
구분 | 개발계 | 스테이지계 |
---|---|---|
Endpoint | Load Balancer | Application Gateway |
Persistence | K8S Statefulset | Azure Database for MySQL |
구성정보 | K8S ConfigMap | Azure App Configuration |
기밀정보 | K8S secret | Azure KeyVault |
Monitoring | 없음 | Application Insight |
Namespace | spring-petclinic | spring-petclinic-stage |
-
본 실습은 설정을 쉽게 확인하고 쉬운 사용성을 확인하기 위해 Azure Portal 에서 작업수행
-
Azure Kubernetes Service 생성
-
Dev/Test
-
ACR 생성 후 Attach가능
az aks update -n <your-cluster> -g <your-resource-group> --attach-acr <acr-name>
-
Note
실제 구축 시 bicap
디렉토리의 IaC코드 활용
혹은
AKS Constructor Helper로 Provisioning 자동화 가능
https://azure.github.io/AKS-Construction/?deploy.deployItemKey=deployArmCli
혹은
az deployment group create -g <your-resource-group> --template-uri https://github.com/Azure/AKS-Construction/releases/download/0.9.0/main.json --parameters \
resourceName=spring-cluster \
upgradeChannel=stable \
agentCountMax=20 \
omsagent=true \
retentionInDays=30
az login
az aks get-credentials --resource-group <your-resource-group> --name <your-cluster>
kubectl get nodes
-
<Kubernetes resources>
> Create > Create a starter application -
샘플앱 살펴보기
kubectl run busybox -i --tty --image=busybox --restart=Never --rm -- sh kubectl run curl --rm -i --tty --image=curlimages/curl -- sh kubectl logs <pod> kubectl describe po <pod> kubectl get po -o yaml
- 마이크로서비스로 분리, 각 서비스는 REST API로 통신,
api-gateway
가 Frontend 역할 및 API중재.
mvn clean package -DskipTests
export REPOSITORY_PREFIX=<your-registry>.azurecr.io/petclinic
cd spring-petclinic-customers-service && docker build -t ${REPOSITORY_PREFIX}/spring-petclinic-cloud-customers-service . && cd ..
cd spring-petclinic-vets-service && docker build -t ${REPOSITORY_PREFIX}/spring-petclinic-cloud-vets-service . && cd ..
cd spring-petclinic-visits-service && docker build -t ${REPOSITORY_PREFIX}/spring-petclinic-cloud-visits-service . && cd ..
cd spring-petclinic-api-gateway && docker build -t ${REPOSITORY_PREFIX}/spring-petclinic-cloud-api-gateway . && cd ..
Important
OSX M1 맥북에서 Docker 빌드할 때 --platform linux/amd64
파라미터를 반드시 넣어야 함.
혹은 buildx
를 통해 멀티 플랫폼 빌드 수행 https://www.docker.com/blog/how-to-rapidly-build-multi-architecture-images-with-buildx/
혹은 spring-boot:build-image
goal 사용
export REPOSITORY_PREFIX=<your-registry>.azurecr.io/petclinic
mvn spring-boot:build-image -DREPOSITORY_PREFIX=${REPOSITORY_PREFIX} -DskipTests
export REPOSITORY_PREFIX=<your-registry>.azurecr.io/petclinic
az acr login --name <your-regtistry>
docker push ${REPOSITORY_PREFIX}/spring-petclinic-cloud-customers-service:latest
docker push ${REPOSITORY_PREFIX}/spring-petclinic-cloud-vets-service:latest
docker push ${REPOSITORY_PREFIX}/spring-petclinic-cloud-visits-service:latest
docker push ${REPOSITORY_PREFIX}/spring-petclinic-cloud-api-gateway:latest
kubectl create namespace spring-petclinic
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
helm install vets-db-mysql oci://registry-1.docker.io/bitnamicharts/mysql --set auth.database=service_instance_db
helm install visits-db-mysql oci://registry-1.docker.io/bitnamicharts/mysql --set auth.database=service_instance_db
helm install customers-db-mysql oci://registry-1.docker.io/bitnamicharts/mysql --set auth.database=service_instance_db
Note
Helm으로 mysql설치 시 자동으로 패스워드에 대한 secret생성됨
Helm Chart내 Template에 정의되어 있음. (설명 필요)
- 외부 ACR을 연결할때만 필요, AKS와 Attach했으면 필요없음.
[!NOTE]
#!/bin/bash
# This script requires Azure CLI version 2.25.0 or later. Check version with `az --version`.
# Modify for your environment.
# ACR_NAME: The name of your Azure Container Registry
# SERVICE_PRINCIPAL_NAME: Must be unique within your AD tenant
export containerRegistry=<your-registry>
export servicePrincipal=<your-registry>-sp
ACR_NAME=$containerRegistry
SERVICE_PRINCIPAL_NAME=$servicePrincipal
# Obtain the full registry ID
ACR_REGISTRY_ID=$(az acr show --name $ACR_NAME --query "id" --output tsv)
# echo $registryId
# Create the service principal with rights scoped to the registry.
# Default permissions are for docker pull access. Modify the '--role'
# argument value as desired:
# acrpull: pull only
# acrpush: push and pull
# owner: push, pull, and assign roles
PASSWORD=$(az ad sp create-for-rbac --name $SERVICE_PRINCIPAL_NAME --scopes $ACR_REGISTRY_ID --role acrpull --query "password" --output tsv)
USER_NAME=$(az ad sp list --display-name $SERVICE_PRINCIPAL_NAME --query "[].appId" --output tsv)
# Output the service principal's credentials; use these in your services and
# applications to authenticate to the container registry.
echo "Service principal ID: $USER_NAME"
echo "Service principal password: $PASSWORD"
cd charts
helm create spring-petclinic
Note
draft 도구를 사용하여 자동으로 생성할 수 있음 Helm Library Chart를 사용하여 쉽게 공통화를 쉽게 하고 개발자가 쉽게 끌어쓸수 있음 Helm Guide는 여기를 참고
helm template petclinic-dev charts/petclinic --namespace spring-petclinic
vets:
image:
repository: <your-registry>.azurecr.io/petclinic/spring-petclinic-cloud-vets-service
tag: latest
customers:
image:
repository: <your-registry>.azurecr.io/petclinic/spring-petclinic-cloud-customers-service
tag: latest
visits:
image:
repository: <your-registry>.azurecr.io/petclinic/spring-petclinic-cloud-visits-service
tag: latest
api-gateway:
image:
repository: <your-registry>.azurecr.io/petclinic/spring-petclinic-cloud-api-gateway
tag: latest
...
# helm upgrade --install <릴리즈명> <차트>
helm upgrade --install petclinic-release charts/petclinic --namespace spring-petclinic
test.http
파일로 API테스트.
Note
VSCode의 REST Client Extension 추천
- 클러스터 내 DNS로 API테스트 수행
kubectl run curl --rm -i --tty --image=curlimages/curl:7.73.0 -- sh
$ curl http://customers-service.spring-petclinic.svc.cluster.local:8080/owners
-
서비스 테스트
- api-gateway의 EXTERNAL-IP로 웹브라우저에서 테스트
kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE api-gateway LoadBalancer 10.0.40.187 20.196.249.134 80:30807/TCP 44h customers-db-mysql ClusterIP 10.0.159.153 <none> 3306/TCP 44h customers-db-mysql-headless ClusterIP None <none> 3306/TCP 44h ...
kubectl create namespace spring-petclinic-stage
-
Azure Portal에서
flexible db
로 생성service_instance_db
DB생성.Admin username
과Password
는 별도 메모 필요.
-
service-instance-db
DB 생성
az mysql flexible-server db create --resource-group <your-resource-group> --server-name <your-mysql> --database-name service_instance_db
- Portal에서
<your-mysql>
> Settings > Connect > Connect from your app > JDBC용 URL 참고
Important
mySQL서비스와 SSL통신을 하기 위해 인증서를 지정해야 함.
커넥션 스트링에서 인증서를 다음과 같이 지정함.
sslmode=verify-full&&sslfactory=org.mysqlql.ssl.SingleCertValidatingFactory&sslfactoryarg=classpath:BaltimoreCyberTrustRoot.crt.pem
BaltimoreCyberTrustRoot.crt.pem
는 각 마이크로서비스 별 src/main/resources
에 있음.
- Portal > Application Insights > Create. Resource Mode를
Workspace-base
로 설정 Instrumentation Key
필요- 각 마이크로서비스 별
pom.xml
에 아래 설정 추가
<!-- App Insight -->
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>applicationinsights-runtime-attach</artifactId>
<version>${appcliation-insights.version}</version>
</dependency>
- (선택) 각 마이크로서비스 별
*Application.java
코드에 아래 로직 추가
import com.microsoft.applicationinsights.attach.ApplicationInsights;
...
@SpringBootApplication
@EnableConfigurationProperties(VetsProperties.class)
public class VetsServiceApplication {
public static void main(String[] args) {
ApplicationInsights.attach();
SpringApplication.run(VetsServiceApplication.class, args);
}
}
-
Deployment
환경 변수에APPINSIGHTS_INSTRUMENTATIONKEY
설정values-stage.yaml
에 아래 설정 추가
env: - name: APPINSIGHTS_INSTRUMENTATIONKEY value: <your-instrumentation-key>
- AKS에서 Secret Store CSI Driver와 Managed ID를 활성화 시킴
export aks=<your-cluster>
export rg=<your-resource-group>
az aks enable-addons -a azure-keyvault-secrets-provider -n $aks -g $rg
az aks update -n $aks -g $rg --enable-managed-identity
-
리전, 이름, Standard Tier로 나머지는 디폴트 설정으로 생성
-
클러스터에
--enable-managed-identity
를 활성화하면 아래와 같이 objectId (Managed ID)를 얻을 수 있음.
"identity": {
"clientId": "90e35a2c-3a2e-495a-88a6-9ca1cd5d710a",
"objectId": "668c37cb-ee54-44bf-bc42-03e420240b5d",
"resourceId": "/subscriptions/2f2d6dff-65ac-45fc-9180-bad1e786a763/resourcegroups/~~~~"
}
- KeyVault 서비스에 secret permission을 위 AKS managed ID에 할당함
az keyvault set-policy -n <your-keyvault> --secret-permissions get --object-id 668c37cb-ee54-44bf-bc42-03e420240b5d
- KeyVault에 아래와 같이 secret을 저장함
az keyvault secret set --vault-name <your-keyvault> --name mysql-user --value <user>
az keyvault secret set --vault-name <your-keyvault> --name mysql-pass --value <password>
Secret Driver Class Manifest 파일 secretproviderclass 수정
-
userAssignedIdentityID
에 위 Managed ID의clientId
를 입력 -
tenantID
: 계정의 TenantID 입력- CLI로 확인
az account tenant list
-
secret-provider-class.yaml
샘플
(생략)
...
spec:
provider: azure
secretObjects:
- data:
- key: mysql-user
objectName: mysql-user
- key: mysql-pass
objectName: mysql-pass
secretName: dbsecret
type: Opaque
parameters:
usePodIdentity: "false"
useVMManagedIdentity: "true"
userAssignedIdentityID: "<clientId>"
keyvaultName: "<your-keyvault>"
cloudName: ""
objects: |
array:
- |
objectName: mysql-user
objectType: secret
objectVersion: ""
- |
objectName: mysql-pass
objectType: secret
objectVersion: ""
tenantId: "<your-tenant-id>"
-
생성된
SecretProviderClass
를Volume
으로 Mount. 이 항목은 values.yaml에서 정의할 수 있음. 이 프로젝트는 스테이지계만 KeyVault를 사용하므로values-stage.yaml
에 정의함. -
Volume, Volume Mount 설정 (values-stage.yaml)
(생략)
...
volumes:
- name: secrets-store01-inline
csi:
driver: secrets-store.csi.k8s.io
readOnly: true
volumeAttributes:
secretProviderClass: "azure-secret"
volumeMounts:
- name: secrets-store01-inline
mountPath: "/mnt/secrets-store"
readOnly: true
- mySQL 사용자 및 비밀번호는 위 Secret Provider Class로 생성된
dbsecret
Object 사용 (values-stage.yaml)
...
env
- name: SPRING_DATASOURCE_USERNAME
valueFrom:
secretKeyRef:
name: dbsecret
key: mysql-user
- name: SPRING_DATASOURCE_PASSWORD
valueFrom:
secretKeyRef:
name: dbsecret
key: mysql-pass
<your-kubernetes>
> Settings> Networking > Application Gateway ingress controller Enable ingress controller > 신규로 생성
-
스테이지 환경만 Ingress생성 및 Application Gateway 연결
-
deployment
에ingress
용annotations
인kubernetes.io/ingress.class: azure/application-gateway
추가values-stage.yaml
샘플
api-gateway: env: - name: SPRING_PROFILES_ACTIVE value: "stage" ingress: enabled: true annotations: kubernetes.io/ingress.class: azure/application-gateway hosts: - host: paths: - path: / pathType: Exact tls: []
- Portal > App Configuration > Create
Free
Tier 선택- Operations > Import/Export > Import >
application-for-app-config.yaml
파일 선택 - Settings > Access keys > read only용 Connection String 복사
- 각 마이크로서비스 별
bootstrap.yaml
에 아래 설정 추가
spring:
config:
activate:
on-profile: stage
cloud:
config:
enabled: false
kubernetes:
reload:
strategy: restart-context
enabled: true
azure:
appconfiguration:
enabled: true
stores:
- connection-string: "<your-appconfigration-connection-string>"
Important
가장 나중에 선언된 선언 값이 우선순위가 높고 Overriding됨. 빈 값으로 선언하지 않도록 주의!
helm upgrade --install <릴리즈명> <차트> -f <환경별 구성정보> -f <리전별 구성정보> ...-f <구성정보>
ns spring-petclinic-stage
helm upgrade --install petclinic-stage charts/petclinic -f charts/petclinic/values-stage.yaml --namespace spring-petclinic-stage