Skip to content

Commit d5bbbac

Browse files
committed
Updated deployments
1 parent 3d6038a commit d5bbbac

File tree

4 files changed

+193
-513
lines changed

4 files changed

+193
-513
lines changed

.github/workflows/deploy-azure.yml

Lines changed: 79 additions & 219 deletions
Original file line numberDiff line numberDiff line change
@@ -1,232 +1,92 @@
1-
name: Deploy to Azure
1+
name: Deploy Memgraph on AKS
22

33
on:
44
push:
5-
branches: [ dev ]
5+
branches: [ main ]
66
workflow_dispatch:
77

88
permissions:
9-
id-token: write
9+
id-token: write # OIDC login
1010
contents: read
1111

1212
env:
13-
ENVIRONMENT: dev
14-
AZURE_RESOURCE_GROUP: GitHub
15-
AZURE_LOCATION: germanywestcentral
13+
# Azure authentication
14+
ARM_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
15+
ARM_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
16+
ARM_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
17+
18+
# Stack parameters
19+
ENVIRONMENT: dev
20+
NODE_VM_SIZE: Standard_B2ms # change here if you need a bigger node
1621

1722
jobs:
18-
deploy-infrastructure:
23+
deploy:
1924
runs-on: ubuntu-latest
20-
timeout-minutes: 30 # Add timeout to prevent infinite runs
25+
defaults: { run: { shell: bash } }
26+
2127
steps:
22-
- uses: actions/checkout@v3
23-
24-
- name: Azure Login
25-
uses: azure/login@v2
26-
with:
27-
client-id: ${{ secrets.AZURE_CLIENT_ID }}
28-
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
29-
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
30-
allow-no-subscriptions: false
31-
audience: api://AzureADTokenExchange
32-
auth-type: SERVICE_PRINCIPAL
33-
34-
- name: Setup Terraform
35-
uses: hashicorp/setup-terraform@v2
36-
37-
- name: Terraform Init
38-
run: |
39-
cd infra/azure
40-
terraform init
41-
42-
- name: Import Existing Resources
43-
run: |
44-
cd infra/azure
45-
chmod +x ./import_resources.sh
46-
ENVIRONMENT=${{ env.ENVIRONMENT }} \
47-
SUBSCRIPTION_ID=${{ secrets.AZURE_SUBSCRIPTION_ID }} \
48-
TENANT_ID=${{ secrets.AZURE_TENANT_ID }} \
49-
OBJECT_ID=${{ secrets.AZURE_SP_OBJECT_ID }} \
50-
CI_MODE=true \
51-
./import_resources.sh
52-
53-
- name: Terraform Apply
54-
timeout-minutes: 120 # Increase timeout to 2 hours for AKS node pool operations
55-
run: |
56-
cd infra/azure
57-
# Set TF_PLUGIN_TIMEOUT to increase the timeout for Azure provider operations
58-
export TF_PLUGIN_TIMEOUT=120m
59-
terraform apply -auto-approve \
60-
-var="environment=${{ env.ENVIRONMENT }}" \
61-
-var="memgraph_username=${{ secrets.MEMGRAPH_USERNAME }}" \
62-
-var="memgraph_password=${{ secrets.MEMGRAPH_PASSWORD }}" \
63-
-var="subscription_id=${{ secrets.AZURE_SUBSCRIPTION_ID }}" \
64-
-var="tenant_id=${{ secrets.AZURE_TENANT_ID }}" \
65-
-var="object_id=${{ secrets.AZURE_SP_OBJECT_ID }}"
66-
67-
- name: Get AKS Credentials
68-
run: |
69-
# Wait for the AKS cluster to be ready
70-
echo "Waiting for AKS cluster to be ready..."
71-
for i in {1..30}; do
72-
if az aks show --resource-group ${{ env.AZURE_RESOURCE_GROUP }} \
73-
--name aks-ai-agent-${{ env.ENVIRONMENT }} --query "provisioningState" -o tsv | grep -q "Succeeded"; then
74-
echo "AKS cluster is ready"
75-
break
76-
fi
77-
echo "Waiting for AKS cluster to be ready (attempt $i)..."
78-
sleep 10
79-
done
80-
81-
# Get credentials
82-
az aks get-credentials --resource-group ${{ env.AZURE_RESOURCE_GROUP }} \
83-
--name aks-ai-agent-${{ env.ENVIRONMENT }}
84-
85-
- name: Create K8s Secret for Memgraph
86-
run: |
87-
# Check if kubectl is working and the cluster is accessible
88-
if ! kubectl get nodes &>/dev/null; then
89-
echo "Cannot connect to Kubernetes cluster. Waiting for it to become available..."
90-
for i in {1..10}; do
91-
sleep 15
92-
if kubectl get nodes &>/dev/null; then
93-
echo "Successfully connected to Kubernetes cluster"
94-
break
95-
fi
96-
echo "Attempt $i: Still waiting for Kubernetes cluster..."
97-
if [ $i -eq 10 ]; then
98-
echo "Failed to connect to Kubernetes cluster after multiple attempts. Continuing anyway..."
99-
fi
100-
done
101-
fi
102-
103-
# Create a credentials hash to force pod restart when credentials change
104-
CREDENTIALS_HASH=$(echo -n "${{ secrets.MEMGRAPH_USERNAME }}${{ secrets.MEMGRAPH_PASSWORD }}" | sha256sum | awk '{print $1}')
105-
echo "CREDENTIALS_HASH=$CREDENTIALS_HASH" >> $GITHUB_ENV
106-
107-
# Create secret directly using kubectl command
108-
kubectl create secret generic memgraph-credentials \
109-
--from-literal=username="${{ secrets.MEMGRAPH_USERNAME }}" \
110-
--from-literal=password="${{ secrets.MEMGRAPH_PASSWORD }}" \
111-
--dry-run=client -o yaml | kubectl apply -f -
112-
113-
echo "Memgraph credentials secret created successfully"
114-
115-
- name: Deploy to AKS
116-
run: |
117-
# Replace the placeholder with the actual credentials hash and environment
118-
cat infra/k8s/memgraph.yaml | \
119-
sed "s/\${CREDENTIALS_HASH}/$CREDENTIALS_HASH/g" | \
120-
sed "s/\${ENVIRONMENT}/${{ env.ENVIRONMENT }}/g" > memgraph_deploy.yaml
121-
122-
# Split the manifest into PVC and non-PVC resources
123-
csplit -z -f part_ memgraph_deploy.yaml "/^---$/" '{*}'
124-
125-
# Apply PVCs only if they do not exist
126-
for f in part_*; do
127-
if grep -q 'kind: PersistentVolumeClaim' "$f"; then
128-
PVC_NAME=$(grep 'name:' "$f" | head -1 | awk '{print $2}')
129-
if kubectl get pvc "$PVC_NAME" &>/dev/null; then
130-
echo "PVC $PVC_NAME already exists, skipping creation."
131-
else
132-
kubectl apply -f "$f"
133-
fi
134-
else
135-
kubectl apply -f "$f"
136-
fi
137-
done
138-
139-
# Force restart if the deployment already exists
140-
POD_NAME=$(kubectl get pods -l app=memgraph -o jsonpath="{.items[0].metadata.name}" 2>/dev/null || echo "")
141-
if [[ -n "$POD_NAME" ]]; then
142-
echo "Forcing restart of existing Memgraph pod..."
143-
kubectl delete pod $POD_NAME
144-
fi
145-
146-
# Remove the temporary files
147-
rm memgraph_deploy.yaml part_*
148-
149-
- name: Verify Deployment
150-
run: |
151-
echo "Checking deployment status..."
152-
kubectl get pods
153-
kubectl get services
154-
155-
echo "Waiting for Memgraph pod to be ready (may take up to 10 minutes)..."
156-
# Check for failed pods with a simpler approach that doesn't rely on complex jsonpath
157-
FAILED_PODS_FAILED=$(kubectl get pods -l app=memgraph --field-selector=status.phase=Failed -o jsonpath="{.items[*].metadata.name}" 2>/dev/null || echo "")
158-
FAILED_PODS_CRASH=$(kubectl get pods -l app=memgraph -o jsonpath="{.items[?(@.status.containerStatuses[0].state.waiting.reason=='CrashLoopBackOff')].metadata.name}" 2>/dev/null || echo "")
159-
160-
FAILED_PODS="$FAILED_PODS_FAILED $FAILED_PODS_CRASH"
161-
if [[ -n "$FAILED_PODS" ]]; then
162-
echo "Found failed pods, cleaning up before proceeding:"
163-
for pod in $FAILED_PODS; do
164-
if [[ -n "$pod" ]]; then
165-
echo "Deleting failed pod: $pod"
166-
kubectl delete pod $pod
167-
fi
168-
done
169-
echo "Waiting for cleanup to complete..."
170-
sleep 30
171-
fi
172-
173-
# Wait for pod to be ready with increased timeout
174-
if ! kubectl wait --for=condition=ready pod -l app=memgraph --timeout=10m; then
175-
echo "Error: Memgraph pod did not become ready within the timeout period."
176-
echo "Checking Memgraph pod logs:"
177-
POD_NAME=$(kubectl get pods -l app=memgraph -o jsonpath="{.items[0].metadata.name}" 2>/dev/null || echo "")
178-
179-
if [[ -n "$POD_NAME" ]]; then
180-
echo "Pod details:"
181-
kubectl describe pod $POD_NAME
182-
183-
echo "Pod logs:"
184-
kubectl logs $POD_NAME --tail=100
185-
else
186-
echo "No Memgraph pod found to check logs."
187-
fi
188-
189-
echo "Checking node resource utilization:"
190-
kubectl describe nodes
191-
192-
echo "Deployment verification failed! Please check the Kubernetes cluster's resources and capacity."
193-
exit 1
194-
fi
195-
196-
echo "Memgraph deployment successful!"
197-
198-
echo "Waiting for LoadBalancer to expose an address..."
199-
for i in {1..45}; do
200-
EXTERNAL_IP=$(kubectl get service memgraph -o jsonpath='{.status.loadBalancer.ingress[0].ip}' 2>/dev/null || echo "")
201-
DNS_NAME=$(kubectl get service memgraph -o jsonpath='{.status.loadBalancer.ingress[0].hostname}' 2>/dev/null || echo "")
202-
if [[ -n "$EXTERNAL_IP" || -n "$DNS_NAME" ]]; then
203-
HOST=${EXTERNAL_IP:-$DNS_NAME}
204-
echo "Memgraph is accessible at: ${HOST}:7687"
205-
# make host usable by subsequent steps
206-
echo "MEMGRAPH_URI=${HOST}" >> $GITHUB_ENV
207-
echo "Performing basic connectivity test..."
208-
if nc -z -w 5 ${HOST} 7687; then
209-
echo "Successfully connected to Memgraph on port 7687!"
210-
else
211-
echo "Warning: Could not connect to Memgraph on port 7687. The service may not be fully ready yet."
212-
fi
213-
break
214-
fi
215-
echo "Waiting for address (attempt $i)..."
216-
sleep 10
217-
done
218-
219-
if [[ -z "$EXTERNAL_IP" && -z "$DNS_NAME" ]]; then
220-
echo "Warning: LoadBalancer address not available within timeout."
221-
kubectl describe service memgraph
222-
else
223-
MEMGRAPH_HOST=${EXTERNAL_IP:-$DNS_NAME}
224-
echo "=========================================================="
225-
echo "Memgraph Connection Information:"
226-
echo "Host: $MEMGRAPH_HOST"
227-
echo "Port: 7687 (Bolt), 7444 (HTTP API), 3000 (UI)"
228-
echo "Username: ${{ secrets.MEMGRAPH_USERNAME }}"
229-
echo "Password: [Configured in secrets]"
230-
echo "Connection URL: bolt://${{ secrets.MEMGRAPH_USERNAME }}@$MEMGRAPH_HOST:7687"
231-
echo "=========================================================="
232-
fi
28+
#─────────────────────────── repo ───────────────────────────
29+
- uses: actions/checkout@v4
30+
31+
#────────────────────── Azure login (OIDC) ──────────────────
32+
- name: Azure login
33+
uses: azure/login@v2
34+
with:
35+
client-id: ${{ env.ARM_CLIENT_ID }}
36+
tenant-id: ${{ env.ARM_TENANT_ID }}
37+
subscription-id: ${{ env.ARM_SUBSCRIPTION_ID }}
38+
auth-type: SERVICE_PRINCIPAL
39+
audience: api://AzureADTokenExchange
40+
41+
#──────────────────────── Terraform ─────────────────────────
42+
- uses: hashicorp/setup-terraform@v2
43+
44+
- name: Terraform init
45+
run: terraform -chdir=infra init
46+
47+
- name: Terraform apply
48+
run: |
49+
terraform -chdir=infra apply -auto-approve \
50+
-var="subscription_id=${{ env.ARM_SUBSCRIPTION_ID }}" \
51+
-var="location=germanywestcentral" \
52+
-var="environment=${{ env.ENVIRONMENT }}" \
53+
-var="node_vm_size=${{ env.NODE_VM_SIZE }}"
54+
55+
#─────────────────── Get AKS kubeconfig ─────────────────────
56+
- name: Pull cluster credentials
57+
run: |
58+
az aks get-credentials \
59+
--resource-group rg-aks-memgraph-${{ env.ENVIRONMENT }} \
60+
--name aks-memgraph-${{ env.ENVIRONMENT }} \
61+
--overwrite-existing
62+
63+
#────────────────── Build / store credentials ──────────────
64+
- name: Build credentials hash
65+
id: hash
66+
run: |
67+
echo "value=$(echo -n '${{ secrets.MEMGRAPH_USERNAME }}${{ secrets.MEMGRAPH_PASSWORD }}' \
68+
| sha256sum | cut -d' ' -f1)" >> "$GITHUB_OUTPUT"
69+
70+
- name: Create / update K8s secret
71+
env:
72+
MEMGRAPH_USERNAME: ${{ secrets.MEMGRAPH_USERNAME }}
73+
MEMGRAPH_PASSWORD: ${{ secrets.MEMGRAPH_PASSWORD }}
74+
run: |
75+
kubectl create secret generic memgraph-credentials \
76+
--from-literal=username="$MEMGRAPH_USERNAME" \
77+
--from-literal=password="$MEMGRAPH_PASSWORD" \
78+
--dry-run=client -o yaml | kubectl apply -f -
79+
80+
#──────────────────── Apply Kubernetes YAML ─────────────────
81+
- name: Apply StorageClass
82+
run: kubectl apply -f infra/k8s/storageclass.yaml
83+
84+
- name: Apply Memgraph manifest
85+
env:
86+
CREDENTIALS_HASH: ${{ steps.hash.outputs.value }}
87+
ENVIRONMENT: ${{ env.ENVIRONMENT }}
88+
run: envsubst < infra/k8s/memgraph.yaml | kubectl apply -f -
89+
90+
#──────────────────────── Smoke test ────────────────────────
91+
- name: Wait for rollout
92+
run: kubectl rollout status deployment/memgraph --timeout=5m

0 commit comments

Comments
 (0)