Passing files to a Microservice
Housekeeping
See the Getting Started documentation for installing and setting up:
microk8s
UCS Tools
Accessing NGC
Setting up repositories
Introduction
In the previous two tutorials Partial Redeployment of App and Restarting Pods on Config Changes, we demonstrated how to add configuration files and expose the fields through the microservice parameters. One problem with this is, if the configuration file contains a lot of parameters, exposing them through the microservice parameters might be cumbersome.
Instead, UCS Tools allow:
microservice to specify that an app should provide entire files/directories and the location to mount them in the microservice containers
app to specify the files/directories from the local filesystem against these requirements and automatically mount the files at expected locations in the microservice container
In this tutorial, we will demonstrate how the above can be achieved via the manifest file, the application YAML and UCS Studio.
This tutorial is a continuation of the tutorial Restarting Pods on Config Changes.
Updating the microservices and application
Update the microservice manifest of the HTTP server microservice http-server
to the following:
type: msapplication
specVersion: 2.5.0
name: ucf.svc.http-server
chartName: http-server
description: http server
version: 0.0.6
tags: []
keywords: []
publish: false
ingress-endpoints:
- name: http
description: REST API endpoint
protocol: TCP
scheme: http
mandatory: False
data-flow: in-out
params:
workingDir: "/localvol"
#> type: string
#> description: Working directory for listing contents
#> flags: mandatory
fileToCreate: somefile.txt
#> type: string
#> description: Name of the file to create in the working directory
#> flags: mandatory
# Files and directories will be mounted with prefix /opt/ext-files/
externalFiles:
- name: app-config.json # File will be available in containers at /opt/ext-files/app-config.json
description: App Configuration file
mandatory: True
isDirectory: False
---
spec:
- name: http-server-deployment
type: ucf.k8s.app.deployment
parameters:
apptype: stateless
- name: http-server-container
type: ucf.k8s.container
parameters:
image:
repository: nvcr.io/nvidia/pytorch
tag: 22.04-py3
command: [sh, -c]
args: [
"WORKING_DIR=$(cat /opt/ext-files/app-config.json | jq -r '.workingDir') && cd $WORKING_DIR && echo $PWD && touch $(FILE_TO_CREATE) && ls && python -m http.server 8080
"]
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: FILE_TO_CREATE
value: $params.fileToCreate
ports:
- containerPort: 8080
name: http
volumeMounts:
- name: localvol
mountPath: /localvol
- name: svc
type: ucf.k8s.service
parameters:
ports:
- port: 8080
protocol: TCP
name: http
- name: localvol
type: ucf.k8s.volume
parameters:
persistentVolumeClaim:
claimName: local-path-pvc
- name: cm-dependencies
type: ucf.appspec.restartPodOnConfigChanges
parameters:
# Add dependency on all configmaps detected in the microservice
addAll: true
# Add dependency on default configmaps for scripts, configs and workload configs
# addDefault: true
# Add dependency on individual configmaps using the configmap names
# configMaps:
# - http-server-configs-cm
There are two changes to the manifest file:
Version of the microservice has been updated
An external file requirement (
externalFiles
) has been addedThe container arguments have been updated to read
workingDir
from the/opt/ext-files/app-config.json
file
Updating the parameters in the application
Create a file at path /home/<>/my-config.json
next to the app.yaml
with following contents:
{
"workingDir": "/etc"
}
Update the app.yaml
file to the following:
specVersion: 2.5.0
version: 0.0.6
doc: README.md
name: server-client-app
description: Server Client Application
dependencies:
- ucf.svc.curl-client:0.0.2
- ucf.svc.http-server:0.0.6
components:
- name: client
type: ucf.svc.curl-client
- name: http-server
type: ucf.svc.http-server
parameters:
workingDir: /var
fileToCreate: someotherfile.txt
files:
app-config.json: /home/<username>/my-config.json
connections:
client/http: http-server/http
The file requirement app-config.json
of the http-server
has been to the newly created file.
Same can be achieved through UCS Studio by selecting the http-server
microservice and setting the file path
from the property window. UCS Studio provides a file browser to select the file.
Building Microservices and Applications and Deploying them
Follow the steps mentioned below but remember to update the version of the http-server
and curl-client
under dependencies
section in app.yaml.
Connecting Microservices - Building Microservices and Applications to build the services and app using CLI
Connecting Microservices - Creating and Building Application using Studio to create and build the app visually using Studio
Connecting Microservices - Deploying and Running Microservices and Application - to deploy the app
Inspecting the Microservices and Application
$ microk8s kubectl get all
NAME READY STATUS RESTARTS AGE
pod/curl-client-curl-client-deployment-569849964-nz598 1/1 Running 0 52m
pod/http-server-http-server-deployment-769c4d5584-xgjg5 1/1 Running 0 41m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.152.183.1 <none> 443/TCP 86d
service/http-server-http-server-deployment-svc ClusterIP 10.152.183.108 <none> 8080/TCP 52m
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/curl-client-curl-client-deployment 1/1 1 1 52m
deployment.apps/http-server-http-server-deployment 1/1 1 1 52m
NAME DESIRED CURRENT READY AGE
replicaset.apps/curl-client-curl-client-deployment-569849964 1 1 1 52m
replicaset.apps/http-server-http-server-deployment-769c4d5584 1 1 1 52m
Checking the logs of the curl-client
pod and the http-server
pod confirms that the path /etc
mentioned in my-config.json
took effect:
$ microk8s kubectl logs --tail -1 -l "app=curl-client-curl-client-deployment"
...
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Directory listing for /</title>
</head>
<body>
<h1>Directory listing for /</h1>
<hr>
<ul>
<li><a href=".pwd.lock">.pwd.lock</a></li>
<li><a href="adduser.conf">adduser.conf</a></li>
<li><a href="alternatives/">alternatives/</a></li>
<li><a href="apt/">apt/</a></li>
100 4386 100 4386 0 0 1070k 0 --:--:-- --:--:-- --:--:-- 1070k
<li><a href="bash.bashrc">bash.bashrc</a></li>
<li><a href="bash_completion.d/">bash_completion.d/</a></li>
<li><a href="bindresvport.blacklist">bindresvport.blacklist</a></li>
<li><a href="ca-certificates/">ca-certificates/</a></li>
<li><a href="ca-certificates.conf">ca-certificates.conf</a></li>
...
<li><a href="someotherfile.txt">someotherfile.txt</a></li>
...
</ul>
<hr>
</body>
</html>
$ microk8s kubectl logs --tail -1 -l "app=http-server-http-server-deployment,microservice_version=0.0.6"
/etc
X11
adduser.conf
alternatives
apt
bash.bashrc
bash_completion.d
bindresvport.blacklist
ca-certificates
ca-certificates.conf
cron.d
cron.daily
debconf.conf
...
This confirms that the file on host filesystem got mounted inside the microservice containers.
Stopping and Cleaning up Microservices and Applications
Finally, to stop and clean up the application we can run:
$ microk8s helm3 uninstall server-client
Some Notes
Informational logs similar to following will be seen when running any helm commands on the output application helm chart. This is because symlinks are used to add the files to the helm chart. These can be safely ignored
walk.go:74: found symbolic link in path: /home/<username>/ucf_tutorial/apps/server-client-app/server-client-app-0.0.6/charts/http-server/files/app-config.json resolves to /home/<username>/my-config.json
This method internally adds the files to a configmap which gets mounted in the microservice pods
Total accumulated size of files & directories being passed to a microservice must be less than 1MiB per microservice. This restriction comes from Kubernetes.
In case you want to pass files / directories larger than 1MiB, you must do so by creating volumes, populating it and setting parameters to mount the volumes on the pods. When doing so, set the the file requirement to special keyword
__FROM_VOLUME__
in the app, so that appbuilder will not run any checks.- name: http-server type: ucf.svc.http-server files: app-config.json: __FROM_VOLUME__