Before you start on adding a new image you need to get an acknowledgement from the maintainers. The first step would be to ensure that we already don't have an image or an issue that has the tool/language that you want to add. After that create an issue explaining how this image would be useful to the community or comment on the existing issue expressing your interest. One of the maintainers will review the issue and acknowledge if you can work on the issue.
You need to have a gitpod account in order to seamlessly contribute to this repo.
NOTE: Maintainers have access to push branches to this repo whereas the community is expected to fork this repo in order to raise a PR.
This repo is already configured with a .gitpod.yml which installs and sets up all the required dependency. It also starts the services that are required to build this repo in dedicated bash shells.
Here is a list of dependencies and tools:
- docker - to start a local registry server
- buildkitd - to help build the images
- dazzle - primary tool used to build docker images
- registry image - a local registry server image
We ship a shell script build-all.sh that can be used to build the images locally. See the following sub sections for usage.
This script will first build the chunks and run tests followed by creation of container images. It uses dazzle
to perform these tasks.
The images will be pushed to the local registry server running on port 5000. You can pull the images using:
docker pull localhost:5000/dazzle:combo
where combo
is the name of the combination defined in dazzle.yaml e.g. full
, clojure
, postgres
.
Often, you would want to test only the chunks that you modify. You can do that with build-chunk.sh using the -c
flag.
./build-chunk.sh -c lang-c -c dep-cacert-update -c lang-go:1.17.5
Above command will build only chunks lang-c
and dep-cacert-update
.
The next step, is to test your changes with ./build-combo.
Sometimes you only want to build one specific combination e.g. the postgresql
or the go
image. You can do that with
./build-combo.sh <comboName> e.g. ./build-combo.sh postgresql
This will build all chunks that are referenced by the go
combination and then combine them to create the go
image.
Execute the following command to build using the default config dazzle.yaml
shipped in this repo:
./build-all.sh
NOTE: Building images locally consumes a lot of resources and is often slow. It might take 1.25 hours to build the images locally. Subsequent builds are faster if the number modified chunks is less.
We use GitHub Actions for our pipelines.
We have a Build pipeline which gets triggered on the following two events:
- Build from Main - On push to the default branch
main
. - Build from Pull Request - On Raising a Pull Request. If it is raised from a fork then it requires an approval from a maintainer.
A new commit to a PR or the main branch always results in execution of all the tests irrespective of the files modified. We use caching per branch in order to speed up subsequent builds. The first push to the Pull Request can take ~1 hr to build. Subsequent pushes would be faster (~25 mins) depending on the number of chunks modified.
We have two Release workflows:
- Build from Main
- On push to the default branch
main
release datetimestamp tagged images to dockerhub. Does NOT update thelatest
tag
- On push to the default branch
- Update latest tags
- Weekly update the
latest
tag of all images in dockerhub with current latest datetimestamp image
- Weekly update the
We do not release any images from pull requests. All the images are built within GH Actions and tested using dazzle.
As evident from previous sections, we use a single GitHub Actions Workflow to build and then release the created images.
Dazzle builds and stores the images as tags of localhost:5000/workspace-base-images
image.
We use an internal Google Artifact Registry to further persist and retag the images with proper names and timestamp.
Post the completion of above step we push the images to our public Docker Hub registry.
You can find all the images under gitpod/
.
Make sure you have read the Before you start section before proceeding further.
A chunk is categorized broadly in two categories:
- lang - A language chunk such as java, clojure, python etc.
- tool - A tool chunk such as nginx, vnc, postgresql etc.
A chunk should be named following the naming convention category-name
.
e.g. a java chunk would be named as lang-java
whereas a postgresql chunk would be named tool-postgresql
.
Follow the below steps to add your chunk:
- Create your chunk directory under ./chunks
- Create a
chunk.yaml
file if your chunk has more than one active versions. You can look at the existing files in this repo for reference e.g. lang-java. - Create a docker file containing instructions on how to install the tool. Make sure you use the default base image like other chunks.
Here is a list of best practices you should keep in mind while adding a chunk:
-
Add variants through
chunk.yaml
if more than one version is popular for the chunk. e.g.java-11
andjava-17
. -
Install specific version of the tool/language.
-
Make sure the user
gitpod
can access the installed tool/lang. -
The last
USER
command of the image should always begitpod
and NOTroot
. -
Always add new path as prefix to existing path. e.g.
ENV PATH=/my-tool/path/bin:$PATH
. Not doing so can cause path conflicts and can potentially break other images. -
DO NOT update the default shell rc files like
.bashrc
unless you are making change in the base layer. -
If you need to create an rc file you should put it in the
.bashrc.d
directory. All the files are sourced from this directory for a bash session. e.g.RUN echo "/etc/mydb/mydb-bashrc-launch.sh" >> /home/gitpod/.bashrc.d/100-my-service-launch.sh
-
Use
gpg
to unpack and store keyrings and add them to apt sources explicitly. e.g.# fetch keyring over https connection and unpack it using gpg's --dearmor option curl -fsSL https://apt.my-secure.org/my-unofficial-repo.gpg.key | sudo gpg --dearmor -o /usr/share/keyrings/my-unofficial-repo.gpg.key # and then add them to a apt key sources list. echo "deb [signed-by=/usr/share/keyrings/my-unofficial-repo.gpg.key] http://apt.my-secure.org/focal/ \ my-unofficial-repo-toolchain main" | sudo tee /etc/apt/sources.list.d/my-unofficial-repo.list > /dev/null
Follow the instructions below to add tests for a chunk:
- Create a
category-name.yaml
file under the tests directory. - Write your tests with proper assertions. You can read more on how to write tests in the dazzle documentation
Here is a list of best practices you should keep in mind while writing a test:
- Test should check the version of the tools and languages and their dependencies that are being installed.
- Test must assert on the exit code i.e. the
status
. - Test must check the existence of directories that are required for the chunk to work.
Adding a combination is easy and only requires you list the base reference and the set of chunks. You can refer to the existing combinations to learn more.
Here is a list of best practices you should keep in mind while adding a combination:
- Use a meaningful name of the combination, it should not conflict with existing names.
- Add
-version
suffix to the combination name if you have variants. e.g.ruby-3
- Use
base
combination as reference rather than other combination unless there is an exception. e.g.full-vnc
is one of the cases which uses thefull
combination rather than thebase
. This is because the vnc combination only adds an extratool-vnc
chunk and nothing else. This combination should always change whenever thefull
combination changes.
The final step to make sure your newly added image gets published is to update these files:
- .github/sync-containers.yml : To publish images from local registry to GAR.
- .github/promote-images.yml : To copy images from GAR to Docker Hub.