-
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