TAP GUI – Techdocs Auto Rendering

Introduction

One of the really great features in Tanzu Application Platform (TAP) is the use of backstage as the UI for the platform.

Backstage is a Developer Platform that is built in a plugin model. amongst the plugins that are included in TAP GUI is the Techdocs plugins.

The Techdocs plugin is a docs-like-code solution built directly into Backstage. This plugin allows for engineers to write their documentation in Markdown files which live together with their code – and with little configuration get a nice-looking doc site in Backstage.

The issue

The Techdocs plugin as great as it is has one serious limitation currently.

In order for the Techdocs plugin to auto render our markdown files into Docs within backstage, it needs access to a docker socket in order to compile the docs.

Many Backstage implementations run simply on a docker host and not in kubernetes making this less of an issue but in TAP, Backstage runs in kubernetes and in kubernetes almost everyone today is using Containerd as the runtime and not docker which makes the use of Techdocs very limiting in TAP GUI.

The official solution

Beyond being able to auto render the docs, the Techdocs plugin allows us to also fetch pre rendered docs which can be hosted in an S3 bucket.

This method is very well documented in the TAP Documentation however the requirement to pre render our docs and have them hosted on an S3 bucket is a pain for multiple reasons:

  1. it requires additional steps beyond a simple git commit
  2. in order to render the docs we need the Techdocs cli which requires npm and npx which are not really “fun” to install
  3. Git is no longer our definitive Point of Truth rather it becomes an S3 bucket which makes things more complex and less transparent

The Workaround

Preface

While playing around with the TAP Learning Center and creating some internal workshops, I noticed that a workshop can have “docker enabled” which basically allows within the workshop sessions, to create and run containers using docker.

After digging into how this works i came to understand they are using a method called Docker-in-Docker or DinD for short.

with this method you basically run a docker socket inside of a container. this allows you to run containers within a container.

Solution

I decided to try and do the same thing for our TAP GUI deployment and see if i could get it to work.

Step #1 Pausing Package Install Reconciliation

The first step in this case is to pause the reconciliation of the relevant Package Install CRs (tap and tap-gui). This is needed as we will be making changes to the TAP GUI deployment and don’t want Kapp Controller to auto reconcile our application back to the packages configuration without our patch.

kubectl patch pkgi tap -n tap-install -p '{"spec":{"paused":true}}' --type=merge
kubectl patch pkgi tap-gui -n tap-install -p '{"spec":{"paused":true}}' --type=merge
Step #2 Create Patch file for TAP GUI

The next step is to create a patch file for our TAP GUI deployment that will:

  1. Add a sidecar container that will run our docker socket
  2. Add an environment variable to the backstage container pointing it at our newly deployed docker socket in the other container
  3. Create 2 emptyDir volumes to share the required files between the 2 containers
cat << EOF > tap-gui-dind-patch.yaml
spec:
 template:
 spec:
 containers:
 - command:
 - dockerd
 - --host
 - tcp://127.0.0.1:2375
 image: docker:dind-rootless
 imagePullPolicy: IfNotPresent
 name: dind-daemon
 resources: {}
 securityContext:
 privileged: true
 runAsUser: 0
 terminationMessagePath: /dev/termination-log
 terminationMessagePolicy: File
 volumeMounts:
 - mountPath: /tmp
 name: tmp
 - mountPath: /output
 name: output
 - name: backstage
 env:
 - name: DOCKER_HOST
 value: tcp://localhost:2375
 volumeMounts:
 - mountPath: /tmp
 name: tmp
 - mountPath: /output
 name: output
 volumes:
 - emptyDir: {}
 name: tmp
 - emptyDir: {}
 name: output
EOF
Step #3 Patch the TAP GUI deployment

The next step is to apply the patch to our TAP GUI deployment:

kubectl patch deploy server -n tap-gui --patch-file tap-gui-dind-patch.yaml
Step #4 Wait for the deployment to rollout the new version

Now that we have made our change to the deployment we can look at the status of our pods in the TAP GUI namespace and wait until the new pod with 2 containers is in the running state and that our old pod with one container is terminated.

To check the status of the rollout and wait for the rollout to finish you can use the command:

kubectl rollout status deployment server -n tap-gui

Future Improvements

Hopefully The Techdocs plugin down the road will not require a docker socket in order to render the docs in real time, however until that happens there are a few improvements to this solution that could be made.

The first one is to implement this patch as a YTT overlay which can be added to our package install. this would allow us to not need to pause the reconciliation of our package installs and instead simply add our solution in a cleaner and more scalable way.

The second one is to have a solution like this built into TAP GUI. I’m not sure if this will happen but I have passed on this POC and the results to the TAP team at VMware and hope that we will see improvements in this area in a future release.

Leave a Reply

%d