iPad and Code-Server in Kubernetes Workflow

Building software with a comfortable device and capable tools

Pushing the limits of mobility and performance has become easier now that the iPad Pro has the Magic Keyboard and Visual Studio Code can be web-based as code-server.

TL;DR: It’s pretty nice but has some shortcomings. This article covers both the workflow and configuration.

Updated to add Kubernetes namespace control

The update article is here and talks about the changes and enhancements made recently. The remainder of this article is still true.

Summary of the workflow

  1. Wake iPad, attach keyboard
  2. Open your code-server url
  3. Checkout repo (or resume existing)
  4. Preview markdown, code spell checker
  5. Cmd+shift+C to open a console and run build, test, etc
  6. Commit updates, get immediate pipeline feedback from GitLab plugin

Not for everyone

Depending on the types of software being developed, the deficiencies in this workflow may overwhelm the benefits. I talk about some of the problems with the workflow later on. If you want to be talked out of it, check that out first. Otherwise, read on for all the neat outcomes and surprises.

Goals

  1. Portable device
  2. Long battery
  3. Drawings and illustrations
  4. Cloudy and containerized work

What it feels like

For the following barrage of screenshots, they are from when I was working on Lab Assistant from my iPad. It seemed like a good place to start recording some of the ease and struggles.

Starting work from iPad, open browser to the code-server ingress URL.

Starting work from iPad, open browser to the code-server ingress URL.

code-server lets you open a new session in a subfolder. Each projects has its own subdirectory.

code-server lets you open a new session in a subfolder. Each projects has its own subdirectory.

When starting on a new project or picking up work on this device for the first time, from that home location pull up a terminal (Cmd+Shift+C) and run git clone. This will create the new directory and fill it up with code. If it’s a microservice situation, create a directory and clone all the various repos into that.

When working in yaml files, code-server has a nice plugin to help navigate.

When working in yaml files, code-server has a nice plugin to help navigate.

Other Visual Studio Code plugins can be used to make the development experience more enjoyable. Since it’s a new IDE for me, I only have YAML, Golang, and GitLab so far.

The best part of this setup is the terminal that allows compiling, linting, testing, and other CLI-driven workflow activities.

The best part of this setup is the terminal that allows compiling, linting, testing, and other CLI-driven workflow activities.

Code-server comes with some git integration, there's additional GitLab functionality from the GitLab plugin.

Code-server comes with some git integration, there's additional GitLab functionality from the GitLab plugin.

After pushing to GitLab, you can view the new branch and create a new merge request from the GitLab interface.

After pushing to GitLab, you can view the new branch and create a new merge request from the GitLab interface.

without leaving the application, the GitLab plugin presents pipeline status notifications.

without leaving the application, the GitLab plugin presents pipeline status notifications.

even if a lot of things are going on in the pipeline.

even if a lot of things are going on in the pipeline.

Sadly, uploading images directly to GitLab is one-at-a-time so squashing commits is much more important. It’s also hard to format images for the web.

Switching gears to blog post

The go workflow is pretty slick. Not a lot of stuff missing with the basics. I’m also trying to use this workflow for making the blog post you’re reading right now. Drafting the text is nice and easy. The spell checker plugin makes it better than my standard Sublime -> MS Word workflow.

The biggest deficiency is image formatting and organization. The iPad is great for making diagrams but once the images are saved, getting them into a web-optimized format and loaded into the repository is a hassle. Especially because you can only upload one file at a time to GitLab’s “upload file” interface. I did realize the WebIDE can do multiple uploads, but only too late.

Once the files are in the repo, they’re gigantic PNG files which should be shrunk, cropped, and optimized for web display. I need to find some tool to plug this gap in my creative work.

Slow and steady gets images from the iPad to code-server. WebIDE multi-upload is an option.

Slow and steady gets images from the iPad to code-server. WebIDE multi-upload is an option.

After uploading the images, renaming them and adding references, it’s time to take a look at what was built.

Start the hugo server with some arguments to allow external connections to the ingress.

Start the hugo server with some arguments to allow external connections to the ingress.

Every change to the code is detected and the site is rebuilt. Since code-server saves the files every time you stop typing, it leads to a lot of rebuilds. The good news is that they take a dozen milliseconds each.

Change detected, rebuilding site.
2020-07-11 19:51:23.996 +0000
Source changed "/home/coder/www-brownfield-dev/content/post/2020-07-11-ipad-code-server-workflow.md": WRITE
Total in 15 ms
Pull up the review app and enjoy live updates.

Pull up the review app and enjoy live updates.

This review app URL in my configuration is tied to a DNS and internal IP address so it’s only accessible to me and others within my network or on a VPN. If you’re working on something public, exposing and sharing the review app may help with reviews and collaboration. It’s probably easier to just use GitLab’s review apps in that case though.

Workflow conclusions

The bottom line is that using an 11-inch iPad Pro with the magic keyboard is a nice way to work comfortably anywhere. Even if the work is relatively intensive coding or authoring.

Screen time for them, productive screen time for me.

Screen time for them, productive screen time for me.

I will continue to use this workflow for a month or two and update about what enhancements come up or if I abandon it eventually.

The rest of this article is about how I arrived at this setup, what it took to get it configured, and how I plan on managing it.

How things were

For the past few years, I’ve been trying to find a lightweight way to get all the benefits of cloud and remote computing while having a comfortable and minimal developer experience. Small devices that were attempted in the past had too many compromises related to performance and feedback.

The prior evaluations have been erratic because it’s tough to tell which combination of physical devices and services can yield a favorable result. Here are some of the things I’ve tried that didn’t pan out.

All of the below are working from an iPad using various Apps:

  1. MacBook 11 inch air: Screen was very low resolution, performance lacking
  2. MacBook 12 inch: At the time, I had a requirement for windows development and the devices (even i7) couldn’t seem to keep up with visual studio in debug mode plus a database
  3. iPad GitLab’s built-in WebIDE: lack of terminals and listing and compilers, feedback loop through pipelines is too slow
  4. iPad app Working Copy for git repos: great repo management and multi-file workflow, same lack of terminals and pipeline-based feedback
  5. iPad app Screens with full MacOS on the tiny screen: native workflow so pretty good but exceptionally expensive and clipboard troubles make it frustrating
  6. iPad app Prompt to use a Linux shell to do things: good for administrative but session time-outs and multi-file editing is poor experience

I was recently convinced to try Visual Studio Code and noticed that it has a code-server hosted web editor option. Evaluation time!

Setting up code-server

The Visual Studio Code installation is a regular software installer on MacOS. Just install it. Super easy.

The code-server installation has some options like a simple web server that runs on the same Mac system. I consider this to be a copy of the Screens workflow so I’m not going to try this.

There is a code-server installation option that is to run as a container. This piqued my interest since containers are neat and flexible. This can be combined with the GitLab CI pipeline to build replacement custom containers to increase the built-in capabilities. Linuxserver.io offers this with a templating/overlay mechanism to make some of the same enhancements I have done.

Why not Kubernetes?

In the interest of doing everything the hardest way imaginable, I took the code-server docker container and spun it up in my local Kubernetes cluster so I could benefit from the infrastructure.

  1. Ingress to a friendly domain name
  2. Certificates issued from Lets Encrypt
  3. Resilience and fail-over
  4. Ephemeral filesystem as a scratchpad
  5. Persistent storage for home directory

Ingress

The main ingress configuration to access code.p.terharlab.com is set to connect to the code-server service.

I also added a Kubernetes service for 1313 and an Ingress mapping my internal load balancer to that service. Now I can pull up hugo server --bind=0.0.0.0 --appendPort=false --baseURL={hugo ingress} And it will attach to a service. I attached this Hugo port to an internal ingress rather than the public one to keep it walled off from the outside world.

Resilience and fail-over

Since the storage is external to the pod, if the pod moves around, the storage will be re-attached. The kubelet scheduler will make sure a code-server keeps running and if it moves from one node to another, the ingress and services will reconfigure to get traffic to the right place.

Ephemeral filesystem

When running the container, if you want to add something like golang or a different version of python, it’s easy enough. Just run apt-get or download binaries and put them in /usr/local/bin. If there is a problem with the tool, just restart the pod and it’ll go away since /usr and /etc are ephemeral.

I followed the enhancement process below to add go, hugo, kubectl, and helm to the image so I can build my lab-assistant application and post to my blog. This just requires updating the Dockerfile and restarting the pod to get the new container.

Persistent storage

To be sure that the day-to-day configuration updates don’t get lost in the ether when the container restarts, the entire /home/coder directory is in the persistent volume. In my environment, this creates an iscsi volume and attaches it to the container to preserve:

  • dotfiles
  • repositories
  • go (packages)
  • /home/coder/.local/share/code-server
    • extensions
    • logs
    • config files
    • spell checker library

Visual Studio Code plugins

The plugin ecosystem is an important part of this tool.

Code-server doesn’t share a license with Visual Studio so the marketplace is detached. They added a script to scrape GitHub which ends up with most of the plugins being present. I am not a VS Code super-user so missing plugins won’t even register on my radar.

I added the GitLab plugin so repo and pipeline info comes back and links to MRs directly from the coding interface.

There are still a lot of VS code capabilities that I have to explore.

Enhancement of the container workflow

  1. Notice a tool is missing
  2. Head over to my code-server-buildtools image
  3. Add package installer or curl binaries the Dockerfile
  4. Pipeline automatically builds new one
  5. Update the code-server.yml if needed, it includes all the Kubernetes objects.
  6. If no spec changes, open in Kuber and scale replicas to 0, then set it back to 1 (pull policy is always)
  7. If spec is updated, apply the new one
  8. Reload browser and enjoy the new feature

The comparison here would be with the local tooling enhancement workflow where one would download an executable and install it or run brew install or apt-get install. This process requires additional steps but keeps the system cleaner and allows easier roll-back if the tools conflict.

The biggest enhancement that enhances the enhancement workflow is to provide the code-server pod with the ability to manage its own namespace. This way it can add a python 2.7 or hugo 0.69 container or pod and then run specific builds in those images.

Problems

There are several problems that range from minor inconvenience to significant frustration. The

  1. Using safari on the iPad on code-server, it will occasionally get confused about whether it’s in a typing mode or a selecting mode and has some copy/paste issues at times
  2. The copy/paste issue above leads to ctrl-c not killing processes like hugo server
  3. Adding picture files from the iPad doesn’t work through code-server, doesn’t seem to have a concept of uploads
  4. Changes to the underlying image require restarting the pod (pull policy is always, but can’t kill it from within)
  5. The git menu doesn’t scroll and only goes down to “stash” so a few options at the bottom are inaccessible
  6. Docker build steps are not allowed inside my Kubernetes cluster so I rely on GitLab.com’s runners and container registry (cluster nodes use my token to pull private project containers)
  7. I touch my MacBook screen to scroll and zoom occasionally and have to wipe off finger prints and smudges

Feedback and contributions are welcome!