Custom Gitpod Images

Some companies can work on the bleeding edge of new technology and use a number of technologies because they can fulfill a copyleft license or they have a higher risk tolerance.

Then there are the regulated industries. Aviation, government contracting, finance, and a myriad more have specific requirements to meet in order to stay in compliance in government oversight. Aviation and health care have to submit completely reproducible code, Finance has to measure each version change in code to ensure it doesn't impact reporting and security, and government has varying regulations based on which department or authority it's under. In many of these, a developer unintentionally using something they shouldn't can cause dire risks to the compliance their industry requires.

How can we prevent this?

Break it down!

I promise this isn't a food blog, however, everyone understands food analogies, right?

My partner is violently allergic to certain mushrooms. She's been in urgent care because of a chef deciding to replace Portabellas with Morels before and suffice it to say, it's not pretty. I also have another friend who can eat most things, but is sensitive to a few things, such as most gluten products and garlic. It's not quite urgent care, but she is completely miserable, and it's fun for no one.

So, when we go somewhere, we have to ask questions to the server, who goes back to the chef to make sure that the mushroom cream is without morels and that the tikka doesn't have garlic. What happens if a chef forgot, doesn't know, or simply doesn't care? Someone is miserable.

So, when we cook at home, we make sure to cook with things that are approved by everyone. A pasta dish with chickpea pasta, vegetables, non-morel mushrooms, and no garlic in the sauce means everyone is happy. (Incidentially, chickpea pasta is pretty good, tell your friends)

Using this private recipe and others we've made along the way, we don't worry, don't have to check ingredient lists, and can trust we'll all be able to hang out without worrying someone will physically need to check out. It's safe, we've all agreed on it, and we can share it pretty consistently.

Photo by Christine Siracusa / Unsplash

Back to the Corporate World

For the corporate equivalent, this means that your recipe, versions of software, needs to be consistent for everyone to tolerate it. The last thing you want to do is use a newer version of Javascript that make your compliance person feel upset or use the latest version of a software that then introduces a breaking change on release day. We usually do this by controlling the versions of software being used. You may decide, as an organization, that Typescript 4.4.4 is approved, but not necessarily others.

However, I have been downhill of having to change my whole machine because of an architecture or compliance decision. As a developer, you may forget custom packages you had to build, or an old restore might have a version your organization doesn't like, or brew auto updates you to the newest NodeJS and suddenly your code is amazing and woefully incompliant. Your entire development experience goes down the tube and you blame compliance, who blames architecture, who blames the developers, and along the way everyone is upset.

How Gitpod can fix this

I promise, this isn't a Gitpod blog either, but it has a cool set of features here we can use.

Gitpod, in addition to launching your environment for you, can let you build a custom workspace to launch inside. By default, it contains a ton of very useful tools, but if you need to be able to reproduce while limiting to approved tools, you can build a custom image. For an example, I built a Typescript one with the AWS CDK that uses specific (yet randomly chosen) versions.

GitHub - martyjhenderson/gitpod-custom-typescript
Contribute to martyjhenderson/gitpod-custom-typescript development by creating an account on GitHub.

Digging into the Dockerfile specifically

FROM gitpod/workspace-base
RUN gpg --keyserver keys.openpgp.org --recv-keys BC6B641A9D1AA1277130025ED9497100C5AC1B0F


# Manually install NodeJS from nvm
ENV NODE_VERSION=14.18.2
RUN curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | PROFILE=/dev/null bash \
    && bash -c ". .nvm/nvm.sh \
        && nvm install $NODE_VERSION \
        && nvm alias default $NODE_VERSION"

# Install Typescript
ENV TS_VERSION=4.4.4
RUN curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | PROFILE=/dev/null bash \
    && bash -c ". .nvm/nvm.sh \ 
    && nvm use $NODE_VERSION \
    && npm i -g typescript@$TS_VERSION"

# Install AWS CDK for Typescript
ENV CDK_VERSION=2.1.0
RUN curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | PROFILE=/dev/null bash \
    && bash -c ". .nvm/nvm.sh \ 
    && nvm use $NODE_VERSION \
    && npm i -g aws-cdk@$CDK_VERSION"

# Make node accessible from path

ENV PATH=$PATH:/home/gitpod/.nvm/versions/node/v${NODE_VERSION}/bin

What this does is pull down the "base" workspace image for Gitpod. This is stripped of common tools like languages or Docker and has only what is needed to run.

In this file, I import a GPG key (mine!). In corporate environments, this is where you import your keyfiles, certificates, and other things that your environments need to connect. You can also include connection information, modified hosts files, or even certain VPNs here.

Then I create environment variables and use nvm to install Node, Typescript, and the AWS CDK for typescript. Thanks to those environment variables, when it builds, it has those specific version. If I want to get newer versions, such as using node 17, I can edit that line and build and the new workspace will have this. It will also ONLY have these when built, so in this case, no Terraform or Python, just AWS CDK. This prevents the use of certain Shadow IT that might be unapproved (though a user could add it after and that can be resolved in other ways outside of this particular post).

So, I build this image and push it to a repository (martyjhenderson/gitpod-typescript in this case) and then...what?

Gitpod.yml

So, let's go back to where you're actually writing your code. In my example, I have a little Hello World in typescript using Gitpod.

GitHub - martyjhenderson/gitpod-dockerfile-demo: A demo using a custom dockerfile
A demo using a custom dockerfile. Contribute to martyjhenderson/gitpod-dockerfile-demo development by creating an account on GitHub.

What you may notice is that this runs! If you've followed my other blog posts on Gitpod, you'll notice that the Gitpod.yml has a few things in it to make it run tsc hw.ts and then node hw.js to give you a nice little Hello, World! in the terminal. Pretty sweet, really.

However, the very first line of that gitpod.yml is

image: martyjhenderson/gitpod-typescript:0.1.1

What this is doing is grabbing this image from Dockerhub and using it instead of the normal Gitpod image. It now only contains what I built originally. Go ahead and open it in Gitpod (it may take a moment to load if I recently updated the image and prebuilds haven't kicked in) and try the version controls

tsc -v for the Typescript version

npm version for the NodeJS version

cdk --version for the AWS CDK version

You'll notice they match the build of the image. Success!

What does this mean?

You can keep your developers happy!

Seriously, by baking the approved version into a custom gitpod image as well as your company keys and putting it in a (private) company repository, your devs don't have to worry if they're out of compliance with acceptable version of software that your are telling regulators or are in your Tier 2 documents. They need to simply make sure they are using your custom gitpod image and all your reports go smoothly and everyone is happy - just like chickpea spaghetti night here with my partner and friends.

...okay, maybe I should start a food blog.

Until then, consider using this to make compliance and reporting easy and making your developers' lives easier to stay in compliance instead of a buffet of emails and sudden surprises come audits!