A Simple Cloud Development Environment

Clay Ratliff
4 min readJul 22, 2023

This is my dead simple Rust development setup on GCP

Image generaetd by Nightcafe

Quick and Dirty

I do a lot of work in the cloud so moving my development environment there makes sense for some things. In addition, it makes my development environment very consistent which is important for things like benchmarking as I can reproduce the exact hardware, control bandwidth, and in general, have more precise control of my test box.

This article is mostly just to show how I create a quick and dirty development box in GCP since I was asked this question. I like the command line so there’s nothing fancy about this; no IDE installs, just a simple how-to on creating a VM that runs a container with the tools you choose. If you want to make it a bit more complex, feel free to add as many bells and whistles as you like.

First..a Dockerfile

As a starting point, for various reasons, I use podman instead of Docker, so I won’t be using Docker as the authenticating client for GCP, but more on that later. First I need to build a docker image so I have a Dockerfile that looks like this:

FROM rust

ARG USERNAME
ARG UID
ARG UGROUP
ARG GECOS

RUN apt-get update -y && apt-get install -y --no-install-recommends \
zsh \
git \
curl \
neovim

RUN groupadd -g ${UGROUP} ${USERNAME}
RUN adduser --force-badname --shell /usr/bin/zsh --uid ${UID} --gecos "${GECOS}" --gid ${UGROUP} ${USERNAME} --disabled-password
RUN chown -R ${USERNAME}: /home/${USERNAME}

USER ${USERNAME}
RUN cd ~/
RUN sh -c "$(curl -fsSL https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"

EXPOSE 28578

This is pretty straightforward. In this case, I’m using the official Rust image on Dockerhub but this can be replaced with whatever base image is appropriate, e.g., python, OpenJDK, etc.

I pass in some arguments to the build command to create the user and group based as well, as you will see shortly.

I then update apt-get and install my base preferred tools for the CLI, configure a group and my user, and switch to that user before installing OMZ. I expose port 28578 because I happened to be working with Redis when I created this one.

Prep for pushing

Using podman I build the file and tag it like so

podman build \
--build-arg USERNAME="$(id -un)" \
--build-arg UID="$(id -u)" \
--build-arg UGROUP="1000" \
--build-arg GECOS="$(id -F)" -t us-east1-docker.pkg.dev/aiven-sa-demo/clays-docker-registry/cr-rust:1.0 .

I pass in the build arguments based on my user account to the build command using the id command. I could have passed in the UGROUP value as well but chose to do this as a hard-coded value.

After that, I authenticate against the GCP Artifact Registry using this command: gcloud auth print-access-token | podman login -u oauth2accesstoken — password-stdin us-east1-docker.pkg.dev/bogus-project/bogus-registry where you would paste your registry information in place of the bogus one listed in the command clip. The tag needs to be in the form LOCATION-docker.pkg.dev/PROJECT-ID/REPOSITORY/IMAGE_NAME on your local image.

Push It Real Good

Pushing the image feels sort of anti-climatic if you were expecting anything clever. It works just as you’d expect it to; podman push us-east1-docker.pkg.dev/aiven-sa-demo/clays-docker-registry/cr-rust:1.0 just like its docker counterpart.

Actual deployment

The most anit-climactic part has come. Now we need to deploy the container in a VM. To do that, you use the create-with-container command like so:

gcloud compute instances create-with-container redis-experiments \
— container-image us-east1-docker.pkg.dev/aiven-sa-demo/clays-docker-registry/cr-rust:1.0

That’s really all there is to it. You now have a development environment deployed to the cloud and containerized. There are clearly a lot of improvements that can be made, like adding configuration files for your tooling or putting all of this into a source code repository and automating the deployments for example, but that’s the gist of it.

Final Note

Some of you may have wondered why I passed a hard-coded value for the group ID to my build command. The steps I outlined above work great in most situations. However, the machine I wrote this article on happens to be a Mac. If I’d used the “$(id -g)” to get the group ID of my account, it would have returned 20. The low numbers that are used on Mac for user accounts would have conflicted with the group IDs used by Linux so I passed a semi-arbitrary high number.

Just to make it more fun, if you’re on a newer Mac using ARM architecture, you won’t be able to create a container from an image built on your Mac because of the architecture differences. Unless you force the VM type to be compatible you’ll need to move the build process itself to the cloud or find a non-ARM machine to create the image.

If you made it this far, give me a clap or a follow to let me know if you found the article useful, and comment below if you have any questions, observations, or find any issues!

--

--

Clay Ratliff

Looking for our dreams in the second half of our lives as a novice sailors as we learn to live on our floating home SV Fearless https://svfearless.substack.com/