Sep 12, 2018
Bring your own (Docker) image to Gitpod
Since we released Gitpod into Public Beta it has been incredibly exciting to see people from all over the world use our service. Even more so with feedback like this:
Of course, there is always room for improvement, especially with a service as new as Gitpod. Luckily, people have started to share their questions and ideas with us on https://github.com/gitpod-io/gitpod. One of the most often asked questions was:
“How do I add tool XYZ to my workspace?”
And indeed that hasn’t been straight forward. You had to:
create a Dockerfile on your machine
build that Dockerfile on your machine
push it to hub.docker.com (no account? Create one first!)
create a branch in your project with a customized .gitpod.yml file which references that specific image
visit gitpod.io/#
get no feedback except ‘Build has status FAILURE’…
rinse and repeat from step 2
That was way too tedious for everyone to start playing around.
Let Gitpod do the heavy lifting
To improve this experience we introducedDockerfile support (#62), which lets you reference your Dockerfile directly from inside your .gitpod.yml file:
image:
file: docker/Dockerfile
Now, Gitpod knows about the Dockerfile and builds that image for you. Whenever you access the repository on Gitpod it checks whether the Dockerfile has been updated and rebuilds the image if needed. When this happens you’ll be shown the log output of the build for easier debugging, too.
An example, please!
Let’s get concrete. As an exercise we’ll use a minimal REST service written inRust using Rocket and Diesel that talks to a PostgreSQL DB. It also has a niceblog post to get started.
The example relies on a very specific nightly build of the Rust compiler from May 2018. Thus, a simple git clone … && cargo build && cargo run won’t get you up-and-running. Of course, you could switch Rust toolchains but then other projects on your machine might stop working. Furthermore, there is more setup and tools to install: A database, a CLI tool… Gitpod to the rescue!
I went to gitpod-io/definitely-gp and added a .gitpod.yml and Dockerfile there. The .gitpod.yml file looks like this:
image:
file: Dockerfile
tasks:
- command: |
echo DATABASE_URL=$DATABASE_URL >> .env
echo ROCKET_ADDRESS=$ROCKET_ADDRESS >> .env
echo ROCKET_PORT=$ROCKET_PORT >> .env
pg_start.sh
diesel setup
cargo build
cargo run
ports:
- port: 8000
It references the Dockerfile next to it, says that the resulting app should be accessible on port 8000 and contains the command executed on workspace startup: set config, start postgres, build and run app (I basically copied those from the repo’s .md file).
The Dockerfile itself inherits from our default image gitpod/workspace-full¹ and contains:
PostgreSQL (+ some configuration for the gitpod user)
specific Rust toolchain
some project specific setup
Here it is:
FROM gitpod/workspace-full:latest
# Install postgres
USER root
RUN apt-get update && apt-get install -y
postgresql
postgresql-contrib
&& apt-get clean && rm -rf /var/cache/apt/* && rm -rf /var/lib/apt/lists/* && rm -rf /tmp/*
# Setup postgres server for user gitpod
USER gitpod
ENV PATH="/usr/lib/postgresql/10/bin:$PATH"
RUN mkdir -p ~/pg/data; mkdir -p ~/pg/scripts; mkdir -p ~/pg/logs; mkdir -p ~/pg/sockets; initdb -D pg/data/
RUN echo '#!/bin/bash\npg_ctl -D ~/pg/data/ -l ~/pg/logs/log -o "-k ~/pg/sockets" start' > ~/pg/scripts/pg_start.sh
RUN echo '#!/bin/bash\npg_ctl -D ~/pg/data/ -l ~/pg/logs/log -o "-k ~/pg/sockets" stop' > ~/pg/scripts/pg_stop.sh
RUN chmod +x ~/pg/scripts/*
ENV PATH="$HOME/pg/scripts:$PATH"
# Project specifics
# Setup diesel_cli
ENV PATH="$HOME/.cargo/bin:$PATH"
RUN cargo install diesel_cli --no-default-features --features postgres
# Some transitive dependencies are very picky: We need the nightly build build on the 2018-04-14, meant for the 2018-04-15
RUN rustup default nightly-2018-04-15
# Set some environment variables
ENV DATABASE_URL=postgres://gitpod@127.0.0.1/rust-web-with-rocket
ENV ROCKET_ADDRESS=0.0.0.0
ENV ROCKET_PORT=8000
# Give back control
USER root
Remember, this is done once per project. Most projects already have those setup descriptions, they are just buried inside their README.
Now whenever anyone accesses the repository through Gitpod, be it a branch, a particular commit, an issue or aPR, they will get a custom workspace with all the tools set up and running, out of the box. Give it a spin!
Once the service has build and is running, we just follow the tutorial:
Open /people: Click Open on the appearing messagebox² and change the path in the integrated browser to http://8000-
/people , click Reload : The query results in an empty [] Hit F1 -> “Open new Terminal” and paste:
curl -XPOST [http://localhost:8000/people](http://localhost:8000/people) -H "Content-Type: application/json" --data '{"id": 123, "first_name": "Jon", "last_name": "Doe", "age": 64, "profession": "Engineer", "salary": 1024}'
- Hit Reload again to see Jon Doe’s people entry
Try it yourself
You can either create a PR ongitpod-io/definitely-gp — or dive right in and create the .gitpod.yml in your repositories! For details on how this works and what is possible please head over to the docs.
¹ It is not required to inherit from that image at all. You can even start with a plain alpine or debian based image. I used it here for convenience.
² Alternatively, go to View -> Ports and click Open
More articles
Journey to Site Reliability Engineering at Gitpod
The SRE team at Gitpod is making the first moves to implement Site Reliability Engineering best practices. We document our approach to implement our very first Service Level Objective.
From Gatsby to Svelte in 3 weeks
A very tight deadline, a small team and a complete redesign - insights into why we use Svelte.
Gitpod Open-Source Sustainability Fund
The truth is free software isn't free. Hours have rates. Rates require payment. What if the high achievers that our digital society is built upon were empowered to become independent artists?