
In this lab, you will build a container image with an example application, deploy it to Kubernetes, and modify the configuration and code of the deployed application.
We will use a tiny shell script as a demo. It returns pong in
response to a request to the /ping
endpoint. You will set up an
environment to use werf and deploy the application to a local
Kubernetes cluster based on Minikube. Finally, you will scale the
running application, modify its code, and see how werf re-deploys it
to the K8s cluster.
Lab Setup
First of all, initiate the lab setup. To do this, click the Lab Setup button in the upper-right corner of the screen. Preparing the lab will take a few minutes, so let's go over some werf basics while the setup is in progress.
About werf
werf is an Open Source tool for building CI/CD processes. It uses the Git repository as a single source of truth (this principle is called Giterminism). With werf, you can build app containers, publish them to the registry, deploy Helm charts to Kubernetes clusters and track the status of the deployment process until it successfully completes.
werf follows the Infrastructure as Code approach by describing the infrastructure declaratively. As a result, the basic pattern of werf-based application deployment is to store both the infrastructure configuration and the app code in the same Git repository. This renders the system fully deterministic and ensures that the resulting system state is identical to the one defined in Git. The changes in the Git repository are automatically propagated to the target environment. werf can work equally well with both remote and local environments.
Preparing the environment
We will be using git in this lab, so let’s configure it:
git config --global user.email "YOUR E-MAIL"
git config --global user.name "YOUR NAME"
Installing werf
Follow the instructions on the werf homepage to install it. First, download the installer:
curl -sSLO https://werf.io/install.sh && chmod +x install.sh
Install werf:
sudo su -
./install.sh --version 1.2 --channel stable
source "$(~/bin/trdl use werf 1.2 stable)"
Check that werf is installed and ready to run:
werf version
Configuring the Container Registry
werf stores the built images in the container registry. We will use the one provided by Docker Hub.
Authorizing in Docker Hub
Create a Docker Hub ID and a private repository named werf-guide-app
to store the built images.
Use the docker login
command to log in to the new repository; enter your Docker Hub username and
password:
docker login
Creating a Secret
To pull images from the private container registry, you have to create a Secret containing user credentials. Note that the Secret must be located in the same namespace as the application.
So first, we need to create a namespace for our application:
kubectl create namespace werf-guide-app
Set the default Namespace so that you don’t have to specify it every time you invoke kubectl
:
kubectl config set-context --current --namespace=werf-guide-app
Next, create a Secret named registrysecret
in the current namespace:
kubectl create secret docker-registry registrysecret \
--docker-server='https://index.docker.io/v1/' \
--docker-username='<DOCKER HUB USERNAME>' \
--docker-password='<DOCKER HUB PASSWORD>'
If you made a mistake when creating a secret, you would have to create it again. But first, delete the existing Secret using the following command:
Building an image
Our sample application's code and all necessary configurations are stored in a tarball. Extract them:
tar -xvzf examples.tar.gz
Navigate to the first example directory:
cd ~/examples/001
About the app
The application directory contains the following files:
start.sh
is the script that returns the response when requested:
Dockerfile
contains all the steps required to build an application image:
The primary werf configuration file, werf.yaml
, specifies Dockerfile
to use when building an application image using werf:
The werf.yaml
file can describe the assembly of multiple images. There are also some additional settings for building an image. You can learn more about them in the documentation.
Building using werf
Initiate the build using the werf build
command:
werf build
Starting the application
You can run the container locally using the built image via the werf run
command:
werf run app --docker-options="-ti --rm -p 8000:8000" -- /app/start.sh
Here, the --docker-options
flag sets the Docker parameters, while the command to run in the container is specified at the end (after two hyphens).
Open a new terminal and check if the application is running:
curl http://127.0.0.1:8000/ping
You should see /pong
in response.
Deploying the application
Navigate to the next example directory:
cd ~/examples/002
About the app
This directory contains several extra files, Helm templates. They define the Kubernetes resources that will be used to deploy our app to the K8s cluster.
The Deployment resource (deployment.yaml
) creates a set of resources for launching the application.
Here are its contents:
{{ .Values.werf.image.app }}
means that the template engine inserts
the full name of the app Docker image into the manifest. Note that
you must use the component name specified in werf.yaml
(app in our
case) to access this value.
werf automatically inserts full image names it is going to build and
other service data into the Helm Chart values (.Values
). You can
access them using the werf
key.
werf only rebuilds images if the added files (those used in the
Dockerfile COPY/ADD
instructions) are changed or if werf.yaml
itself
is changed. The image tag will also change during a rebuild resulting
in the Deployment update. If no changes were made to the files
mentioned above, werf would not initiate the rebuild. The
Deployment and the resources created will not be redeployed since the
latest application version is already running in the cluster.
The Service resource (service.yaml
) allows other applications in the cluster to connect to your application:
The Ingress resource (ingress.yaml
) manages external access to the cluster (unlike a Service in Kubernetes, which defines the application access
policy within the cluster). The Ingress configuration defines what Service to use for external traffic coming to the werf-guide-app.test
domain.
Deploying to Kubernetes
The werf converge
command builds the application
image and deploys it to Kubernetes:
git add . && git commit -m WIP
werf converge --repo <DOCKER HUB USERNAME>/werf-guide-app
Let's check that the application is running and for this, there are two ways to access the application:
- First, you have to find out the application service IP address:
kubectl get -n werf-guide-app services
Now, sending a request to the application should result in a pong
response.
curl http://XXX.XXX.XXX.XXX:8000/ping
- Second, you can access the application through ingress, click on the
app-80
URL under the Lab URLs section and add/ping
at the end of the URL for accessing the application.
kubectl get ingress -n werf-guide-app
You will receive result in a pong
response.
Making changes
In this section, you will make changes to a running application and its infrastructure and learn how the infrastructure-as-code (IaC) approach works.
Navigate to the next example directory:
cd ~/examples/003
Scaling
The web server is a part of the werf-guide-app
Deployment. Let’s see how many its replicas are running:
kubectl get pods
Now, change the number of replicas to 4 right in the Kubernetes configuration:
kubectl edit deployment werf-guide-app
The above command will launch the
text editor (vim). Set
spec.replicas=4
(press i
and edit the number of replicas), save the
file, and close the editor (press ESC
, then :wq
).
Let’s see how many replicas are running now:
kubectl get pods
As you can see, the cluster has been scaled manually. Now, running
werf converge
will bring our Kubernetes cluster back to its original
state – the one specified in our Kubernetes resource configuration
files (manifests):
git add . && git commit -m WIP
werf converge --repo <DOCKER HUB USERNAME>/werf-guide-app
Check the number of running replicas:
kubectl get pods
The number of replicas matches the one specified in the Git repository. As you can see, werf brought the cluster to the state described in the current Git commit. This principle is called Giterminism.
But how does one respect
Giterminism
and scale the cluster in the right fashion? Well,
you have to edit
the deployment.yaml
file and commit the changes to the
repository.
vim .helm/templates/deployment.yaml
Now, commit the changes and rebuild the application:
git add . && git commit -m WIP
werf converge --repo <DOCKER HUB USERNAME>/werf-guide-app
Let’s check how many replicas are running now:
kubectl get pods
What if we decrease their number back to one? Well, let's find out!
Edit the deployment.yaml
file:
Commit the changes and rebuild the application:
git add . && git commit -m WIP
werf converge --repo <DOCKER HUB USERNAME>/werf-guide-app
Making changes to the application
Our application is a basic echo server. When requested using
curl http://XXX.XXX.XXX.XXX:8000/ping
… it responds with the pong
string.
or through the ingress, click on the app-80
URL under the Lab URLs section and add /ping
at the end of URL for accessing the application.
kubectl get ingress -n werf-guide-app
Let’s change the response and redeploy the updated application to
the cluster. Open start.sh
in the text editor and replace the
response with something else (e.g., Hello world
):
vim start.sh
Commit the changes and rebuild the application:
git add . && git commit -m WIP
werf converge --repo <DOCKER HUB USERNAME>/werf-guide-app
Check the result:
curl http://XXX.XXX.XXX.XXX:8000/ping
or through the ingress, click on the app-80
URL under the Lab URLs section and add /ping
at the end of URL for accessing the application.
kubectl get ingress -n werf-guide-app
The server will respond with Hello world
. Congratulations, you did it!
Conclusion
This concludes our lab. In it, you learned how to use werf to organize local application development and speed up the process of deploying applications to a cluster.
Feel free to ask your questions or share ideas and suggestions in our werf chatroom. Note that werf also features detailed guides for different programming languages/frameworks with app source code examples and related infrastructure configurations (IaC).