The magic behind our build-pipeline
This guide should give you a more in depth view of how your app gets deployed
after you pushed to either the staging
or production
branch. What is
described in the following is fully automated and make the life of developers in
the VIS much easier.
Lets start from the beginning. You pushed your new app the first time to the
staging
branch. You have committed a Dockerfile
, a .gitlab-ci.yml
file and
cinit.yml
file. This is mostly all our infrastructure needs from your side to
be able to make your app accessable from the "real world". The first file used
is the .gitlab-ci.yml
file. GitLab has a built-in
tool, where it executes a pipeline of scripts
defined in the .gitlab-ci.yml
. These scripts can be everything, from build,
over tests, to code validations. We provide a
template
consisting of 3 stages: build, deploy and cleanup. All these steps are executed
on our gitlab runner on build.vis.ethz.ch
.
We are going to step through each of them.
- First we have the
build
stage: In there we build the docker image based on yourDockerfile
. Moreover if your app needs certain services such as thepeople-api
,message-api
ormailalias-api
, we generate the needed file, as you have done locally withservice generate
. - In the next step we
deploy
the app: Here we push the generated docker image to our registry, where we store our docker images (similar to Dockerhub). Our registry is reachable atregistry.vis.ethz.ch
. The last step indeploy
is the actual deployment of your app. For this we use helm to generate the deployment of your app. The deployment is the config of how to run your app in our infrastructure. This includes for example how many instance of you app are running, on what domain you app is reachable or simply the name of your app. All this information is gathered from your.gitlab-ci.yml
, where you have specified variables such asVIS_CI_REPLICAS
,VIS_CI_DEPLOYMENT_SUBDOMAIN
orVIS_CI_APP_NAME
. There are many more variables you are able to set. An optional step in thedeploy
stage is to publish services. That means if your app provides a service for other apps such as thepeople-api
you need to be registered, such that other apps know your app exists.
Maybe you wonder where all these instructions come from? If you have a closer
look at your .gitlab-ci.yml
, you might have noticed that at the end of this
file there is
something like
.auto_devops: &auto_devops |
git clone --depth 1 git@gitlab.ethz.ch:vis/cit/ci-framework.git
source ci-framework/ciscript.sh
This connects the pipeline provided by gitlab with the desired steps. If you
are more interested you should have a look at the ciscript.sh
in our
ci-framework.
Now we have our app in the form of a docker images saved in our registry. But
how do we get this app running now? Again this is helm
. It first generates a
kubernetes configuration from some templates which you also find in the
ci-framework
and then it notifies our Kubernetes
that there is a new image
to run. Kubernetes
is a open-soure application
to automatically manage, scale and provide docker containers. Now kubernetes
pulls the newly created docker images, gets rid of the old one and starts up
your app. After some time your app is available on the domain you have
specified in your .gitlab-ci.yml
.
Now where does your program actually run? It's
inside the docker container you just built
which runs inside a Kubernetes worker VM in the VIS's internal network
which runs on one of the 5 main compute nodes
compute0.vis.ethz.ch
tocompute4.vis.ethz.ch
.
And how does my request travel through the network?
If you resolve the website from DNS you will receive 2 IPs which belong to our
routers kube-router-1.vis.ethz.ch
and kube-router-2.vis.ethz.ch
. They are
two VMs routing packets between the Internet and our internal network. Your HTTP
request is decrypted and analysed there. The router then decides to forward it
to a so called
ingress
(this is a kubernetes term). This ingress is a container running nginx on the
Kubernetes worker VMs. The ingress looks up, which
service
(again a kubernetes term) is running this application. A service is nothing more
than an IP address without a machine owning it, a so-called virtual IP. The
ingress sends the request to that IP address. A Linux mechanism called
IPVS then looks up the mapping from
Service IP to your actual container IP. Finally the kernel delivers the request
to your container.