cd ../module04
sed -i 's/YOURACRNAME/'$ACR_NAME'/g' *.yaml
sed -i 's/YOURINGRESSIP/'$INGRESS_IP'/g' *.yaml
Up to this point Microsoft logo in our frontend app has been packaged with container. For situations with much more static content or need for some content management on top of running instances we might leverage shared Volume. This might be more efficient from storage and speed of deployment perspective and content such as images or documents can be managed outside of CI/CD pipelines such as with Content Management System.
Create Azure Files storage in Azure, create share and upload new image.
# variables
# Create storage account
az storage account create -n $STORAGE_NAME \
-g $RESOURCE_GROUP \
--sku Standard_LRS
# Get storage key and create share
export STORAGE_KEY=$(az storage account keys list -g $RESOURCE_GROUP -n $STORAGE_NAME --query [0].value -o tsv
)
az storage share create -n images \
--account-name $STORAGE_NAME \
--account-key $STORAGE_KEY
# Upload image
az storage file upload -s images \
--source ./ms.jpg \
--account-name $STORAGE_NAME \
--account-key $STORAGE_KEY
Create secret with storage connection details
kubectl create secret generic images-secret \
--from-literal=azurestorageaccountname=$STORAGE_NAME \
--from-literal=azurestorageaccountkey=$STORAGE_KEY \
-n myapp
Deploy modified myappspa deployment. We are using Volume implemented by our share and map it to container file system on path where images are. Note that Volume mapping takes precedent over existing files. All created Pods will see the same share.
kubectl apply -f 01-myappspa-deploy.yaml -n myapp
Wait until Deployment object upgrades our environment. Close existing application window and open our app again. You should see image change from Microsoft logo to Azure logo we have mapped to application via share.
Currently for our probes we are accessing root of SPA application which is too big taking away network and storage IO. We might prefer some more lightweight probe to check health status. Also we want to standardize on single url for all apps (/health) and do not want to implement changes in code itself. NGINX allows for configuring such health paths itself.
We want to change NGINX configuration without rebuilding container image. There might more configuration options that we want to tweek during deployment perhaps providing different settings for dev, test and production environment. General rule is not to change container image between environments!
We will solve this by using ConfigMap in Kubernetes. It can consist of key value pair that we can map into our Pod as environmental variables. In our case configuration is actualy more complex configuration file. This is also possible with ConfigMap. First let's use configuration file healthvhost.conf and package it as ConfigMap.
kubectl create configmap healthvhostconf --from-file=healthvhost.conf -n myapp
kubectl describe configmap healthvhostconf -n myapp
First we will use changed Deployment with ConfigMap mapped to file system to proper locaiton where nginx expects configuration file and check it works.
kubectl apply -f 02-myappspa-deploy.yaml -n myapp
Wait for Deployment to redeploy Pods and check our /health URL works.
curl http://$INGRESS_IP.xip.io/health
Looks good. We will now change our probes implementation to point to /health.
kubectl apply -f 03-myappspa-deploy.yaml -n myapp
Suppose now we need to know inside of our Pod what Kubernetes namespace it has been created in. More over we want to write it into file that will be accessible via URL. We will use passing this information via Downward API and also use init container to prepare file before running our main container.
We will add initContainer to our Pod definition. That container will be started before all other containers and Kubernetes will wait for it to finish first. This can used to preload cache or do any other preparations before you are ready to run your main container. We will also leverage Downward API to inject information about used image into Pod as environmental variable. For now init container will just print it on screen so we can capture it in logs.
kubectl apply -f 04-myappspa-deploy.yaml -n myapp
Checkout logs from our info container
kubectl logs myappspa-7b74455b84-rf2c6 -n myapp -c info # Change to your Pod name
Should work. Now we want to put this information as file on our site so we need some way how init container can write to file system that main container can read from. We will use Volume for this, but this time it will not be implemented as outside resource, but rather is Volume valid only on Pod level mounted to both containers. Let's do it.
kubectl apply -f 05-myappspa-deploy.yaml -n myapp
Check it out
curl http://$INGRESS_IP.xip.io/info/namespace.txt
In this example we will investigate how to use Kubernetes to run scheduled batch jobs. This is very useful for certain computation scenarios such as rendering or machine learning, but also for periodical tasks. In our demo we will shedule periodic task to dump data from postgresql into csv file stored on share in Azure storage.
We will reuse storage account we have created for images, but create new share in it.
az storage share create -n exports \
--account-name $STORAGE_NAME \
--account-key $STORAGE_KEY
Than we need to gather connection details you used for creating database in previous modules and store them in Kubernetes secret with naming convention used by psql command line utility.
kubectl create secret generic psql -n myapp \
--from-literal PGUSER=$POSTGRESQL_USER@$POSTGRESQL_NAME \
--from-literal PGPASSWORD=$POSTGRESQL_PASSWORD \
--from-literal PGHOST=$POSTGRESQL_NAME.postgres.database.azure.com \
--from-literal PGDATABASE=todo
Schedule job to run every 2 minutes.
kubectl apply -f 06-export.yaml -n myapp
Job will run every 2 minutes. After while check files in your storage account.
az storage file list -s exports -o table \
--account-name $STORAGE_NAME \
--account-key $STORAGE_KEY
We will try to create horizontally auto-scaled solution for our .NetCore service.
# create namespace for experiment with HPA
kubectl create namespace perf
Create secrets for service's connection string.
# create secrets
kubectl create secret generic cosmos-secret \
--from-literal=cosmosuri=$COSMOSURI \
--from-literal=cosmoskey=$COSMOSKEY \
-n perf
Apply deployment of our webstress service
# deploy
kubectl apply -f 07-webstress.yaml -n perf
# get public IP of service for testing
kubectl get svc -n perf
# create HPA
kubectl autoscale rs webstress --namespace perf --min=1 --max=8 --cpu-percent=50
# monitor HPA
kubectl get hpa --namespace perf -w
Send some "stress" traffic to service.
# you can run fet times this background task ...
curl "[IP ADDRESS]/perf?x=[0-10000]" 2> /dev/null > /dev/null &
# after test you can kill all curl processes
pkill curl
kubectl delete namespace myapp
kubectl delete namespace perf