VMware Tanzu Application Catalog Documentation - Tutorials
VMware Tanzu Application Catalog Documentation - Tutorials
Catalog Documentation -
Tutorials
VMware Tanzu Application Catalog services
VMware Tanzu Application Catalog Documentation - Tutorials
You can find the most up-to-date technical documentation on the VMware by Broadcom website at:
https://docs.vmware.com/
VMware by Broadcom
3401 Hillview Ave.
Palo Alto, CA 94304
www.vmware.com
Copyright © 2024 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its
subsidiaries. For more information, go to https://www.broadcom.com. All trademarks, trade names, service
marks, and logos referenced herein belong to their respective companies. Copyright and trademark
information.
VMware by Broadcom 2
VMware Tanzu Application Catalog Documentation - Tutorials
Contents
VMware by Broadcom 3
VMware Tanzu Application Catalog Documentation - Tutorials
VMware by Broadcom 4
VMware Tanzu Application Catalog Documentation - Tutorials
VMware by Broadcom 5
VMware Tanzu Application Catalog Documentation - Tutorials
Audit trails 76
Conclusion 77
Useful links 77
VMware by Broadcom 6
VMware Tanzu Application Catalog Documentation - Tutorials
VMware by Broadcom 7
VMware Tanzu Application Catalog Documentation - Tutorials
Backup and Restore VMware Tanzu Application Catalog Helm Chart 128
Deployments with Velero
Introduction 128
Assumptions and prerequisites 128
VMware by Broadcom 8
VMware Tanzu Application Catalog Documentation - Tutorials
VMware by Broadcom 9
VMware Tanzu Application Catalog Documentation - Tutorials
VMware by Broadcom 10
VMware Tanzu Application Catalog Documentation - Tutorials
VMware by Broadcom 11
VMware Tanzu Application Catalog Documentation - Tutorials
This section provides information about how to use OSS applications available via VMware Tanzu
Application Catalog.
Backup and Restore Tanzu Application Catalog Helm Chart Deployments with Velero
VMware by Broadcom 12
VMware Tanzu Application Catalog Documentation - Tutorials
Migrate Data Between Kubernetes Clusters with Tanzu Application Catalog and Velero
Intended Audience
This information is intended for everyone who want to get started with Applications provided via
VMware Tanzu Application Catalog. The information is written for users who have a basic
understanding of Kubernetes and are familiar with container deployment concepts. In-depth
knowledge of Kubernetes is not required.
VMware by Broadcom 13
VMware Tanzu Application Catalog Documentation - Tutorials
Introduction
So, you've got your Kubernetes cluster up and running and set up Helm v3.x, but how do you run
your applications on it? This guide walks you through the process of creating your first ever chart,
explaining what goes inside these packages and the tools you use to develop them. By the end of it
you should have an understanding of the advantages of using Helm to deliver your own applications
to your cluster.
For a typical cloud-native application with a 3-tier architecture, the diagram below illustrates how it
might be described in terms of Kubernetes objects. In this example, each tier consists of a
Deployment and Service object, and may additionally define ConfigMap or Secret objects. Each of
these objects are typically defined in separate YAML files, and are fed into the kubectl command
line tool.
A Helm chart encapsulates each of these YAML definitions, provides a mechanism for configuration
at deploy-time and allows you to define metadata and documentation that might be useful when
sharing the package. Helm can be useful in different scenarios:
Let's explore the second and third scenarios by creating our first chart.
VMware by Broadcom 14
VMware Tanzu Application Catalog Documentation - Tutorials
Helm will create a new directory in your project called mychart with the structure shown below. Let's
navigate our new chart (pun intended) to find out how it works.
mychart
|-- Chart.yaml
|-- charts
|-- templates
| |-- NOTES.txt
| |-- _helpers.tpl
| |-- deployment.yaml
| |-- ingress.yaml
| `-- service.yaml
`-- values.yaml
Templates
The most important piece of the puzzle is the templates/ directory. This is where Helm finds the
YAML definitions for your Services, Deployments and other Kubernetes objects. If you already have
definitions for your application, all you need to do is replace the generated YAML files for your own.
What you end up with is a working chart that can be deployed using the helm install command.
It's worth noting however, that the directory is named templates, and Helm runs each file in this
directory through a Go template rendering engine. Helm extends the template language, adding a
number of utility functions for writing charts. Open the service.yaml file to see what this looks like:
apiVersion: v1
kind: Service
metadata:
name: {{ template "fullname" . }}
labels:
chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.externalPort }}
targetPort: {{ .Values.service.internalPort }}
protocol: TCP
name: {{ .Values.service.name }}
selector:
app: {{ template "fullname" . }}
This is a basic Service definition using templating. When deploying the chart, Helm will generate a
definition that will look a lot more like a valid Service. We can do a dry-run of a helm install and
enable debug to inspect the generated definitions:
VMware by Broadcom 15
VMware Tanzu Application Catalog Documentation - Tutorials
Values
The template in service.yaml makes use of the Helm-specific objects .Chart and .Values.. The
former provides metadata about the chart to your definitions such as the name, or version. The latter
.Values object is a key element of Helm charts, used to expose configuration that can be set at the
time of deployment. The defaults for this object are defined in the values.yaml file. Try changing the
default value for service.internalPort and execute another dry-run, you should find that the
targetPort in the Service and the containerPort in the Deployment changes. The
service.internalPort value is used here to ensure that the Service and Deployment objects work
together correctly. The use of templating can greatly reduce boilerplate and simplify your definitions.
If a user of your chart wanted to change the default configuration, they could provide overrides
directly on the command-line:
For more advanced configuration, a user can specify a YAML file containing overrides with the \--
values option.
The service.yaml template also makes use of partials defined in _helpers.tpl, as well as functions
like replace. The Helm documentation has a deeper walkthrough of the templating language,
explaining how functions, partials and flow control can be used when developing your chart.
Documentation
Another useful file in the templates/ directory is the NOTES.txt file. This is a templated, plaintext file
that gets printed out after the chart is successfully deployed. As we'll see when we deploy our first
chart, this is a useful place to briefly describe the next steps for using a chart. Since NOTES.txt is run
through the template engine, you can use templating to print out working commands for obtaining
VMware by Broadcom 16
VMware Tanzu Application Catalog Documentation - Tutorials
Metadata
As mentioned earlier, a Helm chart consists of metadata that is used to help describe what the
application is, define constraints on the minimum required Kubernetes and/or Helm version and
manage the version of your chart. All of this metadata lives in the Chart.yaml file. The Helm
documentation describes the different fields for this file.
RESOURCES:
==> v1/Service
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
example-mychart 10.0.0.24 <nodes> 80:30630/TCP 0s
==> v1beta1/Deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
example-mychart 1 1 1 0 0s
NOTES:
1. Get the application URL by running these commands:
export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePo
rt}" services example-mychart)
export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.
addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT/
The output of helm install displays a handy summary of the state of the release, what objects were
created, and the rendered NOTES.txt file to explain what to do next. Run the commands in the
output to get a URL to access the NGINX service and pull it up in your browser.
VMware by Broadcom 17
VMware Tanzu Application Catalog Documentation - Tutorials
If all went well, you should see the NGINX welcome page as shown above. Congratulations! You've
just deployed your very first service packaged as a Helm chart!
We are going to update the chart to run a todo list application available on Docker Hub. In
values.yaml, update the image keys to reference the todo list image:
image:
repository: prydonius/todo
tag: 1.0.0
pullPolicy: IfNotPresent
As you develop your chart, it's a good idea to run it through the linter to ensure you're following
best practices and that your templates are well-formed. Run the helm lint command to see the
linter in action:
The linter didn't complain about any major issues with the chart, so we're good to go. However, as
an example, here is what the linter might output if you managed to get something wrong:
VMware by Broadcom 18
VMware Tanzu Application Catalog Documentation - Tutorials
This time, the linter tells us that it was unable to parse the values.yaml file correctly. With the line
number hint, we can easily find and fix the bug we introduced.
Now that the chart is once again valid, run helm install again to deploy the todo list application:
RESOURCES:
==> v1/Service
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
example2-mychart 10.0.0.78 <nodes> 80:31381/TCP 0s
==> apps/v1/Deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
example2-mychart 1 1 1 0 0s
NOTES:
1. Get the application URL by running these commands:
export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePo
rt}" services example2-mychart)
export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.
addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT/
Once again, we can run the commands in the NOTES to get a URL to access our application.
VMware by Broadcom 19
VMware Tanzu Application Catalog Documentation - Tutorials
If you have already built containers for your applications, you can run them with your chart by
updating the default values or the Deployment template.
Helm will create a mychart-0.1.0.tgz package in our working directory, using the name and version
from the metadata defined in the Chart.yaml file. A user can install from this package instead of a
local directory by passing the package as the parameter to helm install.
Repositories
VMware by Broadcom 20
VMware Tanzu Application Catalog Documentation - Tutorials
In order to make it much easier to share packages, Helm has built-in support for installing packages
from an HTTP server. Helm reads a repository index hosted on the server which describes what
chart packages are available and where they are located.
We can use the helm serve command to run a local repository to serve our chart.
helm serve
Regenerating index. This may take a moment.
Now serving you on 127.0.0.1:8879
Now, in a separate terminal window, you should be able to see your chart in the local repository and
install it from there:
To set up a remote repository you can follow the guide in the Helm documentation.
Dependencies
As the applications your packaging as charts increase in complexity, you might find you need to pull
in a dependency such as a database. Helm allows you to specify sub-charts that will be created as
part of the same release. To define a dependency, create a requirements.yaml file in the chart root
directory:
Much like a runtime language dependency file (such as Python's requirements.txt), the
requirements.yaml file allows you to manage your chart's dependencies and their versions. When
updating dependencies, a lockfile is generated so that subsequent fetching of dependencies use a
known, working version. Run the following command to pull in the MariaDB dependency we defined:
VMware by Broadcom 21
VMware Tanzu Application Catalog Documentation - Tutorials
Helm has found a matching version in the bitnami repository and has fetched it into the chart's sub-
chart directory. Now when we go and install the chart, we'll see that MariaDB's objects are created
too:
RESOURCES:
==> v1/Secret
NAME TYPE DATA AGE
example5-mariadb Opaque 2 1s
==> v1/ConfigMap
NAME DATA AGE
example5-mariadb 1 1s
==> v1/PersistentVolumeClaim
NAME STATUS VOLUME CAPACITY ACCESSMO
DES AGE
example5-mariadb Bound pvc-229f9ed6-3015-11e7-945a-66fc987ccf32 8Gi RWO
1s
==> v1/Service
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
example5-mychart 10.0.0.144 <nodes> 80:30896/TCP 1s
example5-mariadb 10.0.0.108 <none> 3306/TCP 1s
==> apps/v1/Deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
example5-mariadb 1 1 1 0 1s
example5-mychart 1 1 1 0 1s
NOTES:
1. Get the application URL by running these commands:
export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePo
rt}" services example5-mychart)
export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.
addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT/
Useful links
We've walked through some of the ways Helm supercharges the delivery of applications on
Kubernetes. From an empty directory, you were able to get a working Helm chart out of a single
command, deploy it to your cluster and access an NGINX server. Then, by simply changing a few
lines and re-deploying, you had a much more useful todo list application running on your cluster!
Beyond templating, linting, sharing and managing dependencies, here are some other useful tools
available to chart authors:
Define hooks to run Jobs before or after installing and upgrading releases
VMware by Broadcom 22
VMware Tanzu Application Catalog Documentation - Tutorials
VMware by Broadcom 23
VMware Tanzu Application Catalog Documentation - Tutorials
Introduction
Since Bitnami published its first Docker container in 2015, the techniques for writing Dockerfiles have
significantly evolved. As part of the team which maintains a container catalog with more than 130
apps, I have worked on adapting the containers and their Dockerfiles to meet the community
requirements.
In this tutorial, I will go over these lessons learned, describing some of the best practices and
common pitfalls that you are likely to encounter when developing Dockerfiles, by applying them on
practical examples. First, I will briefly explain some basic concepts that you need to refresh before
examining specific cases. Then, I will walk you through some practical examples, to improve the
build time, the size, and the security of a Docker image. To do that, I have provided you with a
GitHub repository that contains all the files you need, to follow the tips and tricks shown in this post.
What is a Dockerfile?
A Dockerfile is just a blueprint that contains the instructions to build a Docker image. Currently, more
than a million Dockerfiles are on GitHub.
VMware by Broadcom 24
VMware Tanzu Application Catalog Documentation - Tutorials
Every time you build a Docker image, each build step is cached. Reuse cached layers that do not
change in the image rebuild process to improve the build time.
Consistency: If you are consistent designing your images, they are easier to maintain and you
will reduce the time spent when developing new images.
Build Time: Especially when your builds are integrated in a Continuous Integration pipeline
(CI), reducing the build time can significantly reduce your apps' development cost.
Image Size: Reduce the size of your images to improve the security, performance, efficiency,
and maintainability of your containers.
Security: Critical for production environments, securing your containers is very important to
protect your applications from external threats and attacks.
Prerequisites
There are two tools that will help you develop your Dockerfiles. Before starting the tutorial, I advise
you to:
Enable BuildKit
Enable BuildKit
Buildkit is a toolkit which is part of the Moby project that improves performance when building
Docker images. It can be enabled in two different ways:
$ export DOCKER_BUILDKIT=1
{
"features": {
"buildkit": true
}
}
There are plugins that provide these functionalities for almost every Integrated Development
Environment (IDE). Here are some suggestions:
VMware by Broadcom 25
VMware Tanzu Application Catalog Documentation - Tutorials
Atom: linter-docker
The examples are based on building a very simple Node.js application's Docker image using the files
below:
A LICENSE.
A package.json that describes the application and its dependencies (which are basically the
Express NPM module).
FROM debian
# Copy application files
COPY . /app
# Install required system packages
RUN apt-get update
RUN apt-get -y install imagemagick curl software-properties-common gnupg vim ssh
RUN curl -sL https://deb.nodesource.com/setup_10.x | bash -
RUN apt-get -y install nodejs
# Install NPM dependencies
RUN npm install --prefix /app
EXPOSE 80
CMD ["npm", "start", "--prefix", "app"]
Using debian as the base image, it installs nodejs and npm in the system using the apt-get
command. To run the application, it's necessary to install some extra system packages for the
Node.js setup script to work, such as curl, imagemagick, software-properties-common, or gnupg.
Furthermore, it installs vim and ssh packages for debugging purposes.
Once the image has all that it needs to build the application, it installs the application dependencies
and uses the npm start command to start the application. The port 80 is exposed since the
application uses it and it is specified with the expose parameter. To build the Docker image for this
application, use the command below:
Note
You can specify the image tag using the format: IMAGE_NAME:TAG.
VMware by Broadcom 26
VMware Tanzu Application Catalog Documentation - Tutorials
It takes 127.8 seconds to build the image and it is 554MB. We can improve the results by following
some good practices.
Let's try to emulate the process of rebuilding your apps' image to introduce a new change in the
code, so you can understand how the cache works. To do so, edit the message used in the
console.log at server.js and rebuild the image using the command below:
Using the current approach, you can't reuse the build cache to avoid installing the system packages
if a single bit changes in the application's code. However, if you switch the order of the layers, you
will be able to avoid reinstalling the system packages:
FROM debian
- # Copy application files
- COPY . /app
# Install required system packages
RUN apt-get update
...
RUN apt-get -y install nodejs
+ # Copy application files
+ COPY . /app
# Install NPM dependencies
...
Rebuild the image using the same command, but avoiding the installation of the system packages.
This is the result: it takes 5.8 seconds to build and the improvement is significant.
If a single character changed in the README.md file (or in any other file which is in the repository
but is not related to the application), it would result in copying the entire directory into the image
which will disrupt the cache once more.
You have to be specific about the files you copy to make sure that you are not invalidating the
cache with changes that do not affect the application.
...
# Copy application files
- COPY . /app
+ COPY package.json server.js /app
# Install NPM dependencies
...
Note
Use "COPY" instead of "ADD" when possible. Both commands do basically the same
VMware by Broadcom 27
VMware Tanzu Application Catalog Documentation - Tutorials
thing, but "ADD" is more complex: it has extra features like extracting files or
copying them from remote sources. From a security perspective too, using "ADD"
increases the risk of malware injection in your image if the remote source you are
using is unverified or insecure.
The current Dockerfile includes the ssh system package. However, you can access your containers
using the docker exec command instead of ssh'ing into them. Apart from that, it also includes vim
for debugging purposes, which can be installed when required, instead of packaged by default. Both
packages are removable from the image.
In addition, you can configure the package manager to avoid installing packages that you don't
need. To do so, use the --no-install-recommends flag on your apt-get calls:
...
RUN apt-get update
- RUN apt-get -y install imagemagick curl software-properties-common gnupg vim ssh
+ RUN apt-get -y install --no-install-recommends imagemagick curl software-properties-
common gnupg
RUN curl -sL https://deb.nodesource.com/setup_10.x | bash -
- RUN apt-get -y install nodejs
+ RUN apt-get -y install --no-install-recommends nodejs
# Install NPM dependencies
...
On the other hand, it's not logical to have separate steps for updating or installing system packages.
This might result in installing outdated packages when you rebuild the image. So, let's combine them
into a single step to avoid this issue.
...
- RUN apt-get update
- RUN apt-get install -y --no-install-recommends imagemagick curl software-properties-
common gnupg
+ RUN apt-get update && apt-get -y install --no-install-recommends imagemagick curl so
ftware-properties-common gnupg
- RUN curl -sL https://deb.nodesource.com/setup_10.x | bash -
- RUN apt-get -y install --no-install-recommends nodejs
+ RUN curl -sL https://deb.nodesource.com/setup_10.x | bash - && apt-get -y install --
no-install-recommends nodejs
# Install NPM dependencies
...
Finally, remove the package manager cache to reduce the image size:
...
RUN apt-get update && apt-get -y install --no-install-recommends imagemagick curl soft
ware-properties-common gnupg
- RUN curl -sL https://deb.nodesource.com/setup_10.x | bash - && apt-get -y install --
no-install-recommends nodejs
+ RUN curl -sL https://deb.nodesource.com/setup_10.x | bash - && apt-get -y install --
VMware by Broadcom 28
VMware Tanzu Application Catalog Documentation - Tutorials
... The image was reduced to 340MB!! That's almost half of its original size.
Using minideb
Minideb is a minimalist Debian-based image built specifically to be used as a base image for
containers. To significantly reduce the image size, use it as the base image.
- FROM debian
+ FROM bitnami/minideb
# Install required system packages
...
...
# Install required system packages
- RUN apt-get update && apt-get -y install --no-install-recommends imagemagick curl so
ftware-properties-common gnupg
+ RUN install_packages imagemagick curl software-properties-common gnupg
- RUN curl -sL https://deb.nodesource.com/setup_10.x | bash - && apt-get -y install --
no-install-recommends nodejs && rm -rf /var/lib/apt/lists/*
+ RUN curl -sL https://deb.nodesource.com/setup_10.x | bash - && install_packages node
js
# Copy application files
...
As you can see, you saved 63MB more. The image size is now 277MB
Ensuring all the components are packaged with the latest available patches since they are
rebuilt every day.
VMware by Broadcom 29
VMware Tanzu Application Catalog Documentation - Tutorials
Instead of installing the system packages you need to run the application (Node.js in this case), use
the bitnami/node image:
- FROM bitnami/minideb
+ FROM bitnami/node
- # Install required system packages
- RUN install_packages imagemagick curl software-properties-common gnupg
- RUN curl -sL https://deb.nodesource.com/setup_10.x | bash - && install_packages node
js
# Copy application files
...
Maintained images usually have different tags, used to specify their different flavors. For instance, the
bitnami/node image is built for different Node.js versions and it has a prod flavor which includes the
minimal needed packages to run a Node application (see Supported Tags).
Following this example, imagine that the application is requesting node >= 10 in the package.json.
Therefore, you should use the 10-prod tag to ensure that you are using Node.js 10 with the minimal
packages:
- FROM bitnami/node
+ FROM bitnami/node:10-prod
# Copy application files
...
These are the results: 48MB have been saved since the image size is now 229MB. With this crucial
adjustment, concerns about system packages are no longer necessary.
FROM bitnami/node:10-prod
# Copy application files
COPY package.json server.js /app
# Install NPM dependencies
RUN npm install --prefix /app
EXPOSE 80
CMD ["npm", "start", "--prefix", "/app"]
The current status of the sample Dockerfile shows two kinds of identifiable build steps:
Building the application from source code and installing its dependencies.
To continue improving the efficiency and size of the image, split the build process into different
stages. That way, the final image will be as simple as possible.
VMware by Broadcom 30
VMware Tanzu Application Catalog Documentation - Tutorials
Using multi-stage builds is good practice to only copy the artifacts needed in the final image. Let's
see how to do it in this example:
FROM bitnami/node:10-prod
COPY --from=builder /app/package.json /app/server.js /app
COPY --from=builder /app/node_modules /app/node_modules
EXPOSE 80
CMD ["node", "/app/server.js"]
Using bitnami/node:10 to build our application, I added AS builder to name our first stage
"builder". Then, I used COPY --from=builder to copy files from that stage. That way, the artifacts
copied are only those needed to run the minimal image bitnami/node:10-prod.
This approach is extremely effective when building images for compiled applications. In the example
below, I have made some tweaks to dramatically decrease the image size. The sample image is the
one that builds Kubeapps Tiller Proxy, one of the core components of Kubeapps:
ARG VERSION
FROM scratch
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /tiller-proxy /proxy
EXPOSE 80
CMD ["/proxy"]
The final image uses scratch (which indicates that the next command in the Dockerfile is the first
filesystem layer in the image) and it contains only what we need: the binary and the SSL
certificates.
Note
Use ARG and --build-arg K=V to modify your builds from the command line.
VMware by Broadcom 31
VMware Tanzu Application Catalog Documentation - Tutorials
The final image size is only 37.7MB!! If you include both building and running instructions in the
same image, the image size will be > 800MB.
Reuse those artifacts built on the builder stage to create platform-specific images. For instance,
following the Kubeapps Tiller Proxy example, use a Dockerfile to create different images for
different platforms. In the Dockerfile below, Debian Stretch and Oracle Linux 7 are the platforms
specified for the build:
...
FROM oraclelinux:7-slim AS target-oraclelinux
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /tiller-proxy /proxy
EXPOSE 80
CMD ["/proxy"]
In the build commands, just add the --target X flag to indicate which platform you want to build the
image for:
Using a single Dockerfile, you built images for two different platforms, while keeping the build
process very simple.
This approach prevents malicious code from gaining permissions in the container host. It also allows
running containers on Kubernetes distributions that don’t allow running containers as root, such as
OpenShift. For more information about the reasons to use a non-root container, check these blog
posts:
To convert the Docker image into a non-root container, change the default user from root to
nonroot:
...
EXPOSE 80
+ useradd -r -u 1001 -g nonroot root
+ USER nonroot
CMD ["node", "/app/server.js"]
VMware by Broadcom 32
VMware Tanzu Application Catalog Documentation - Tutorials
...
Note
File permissions: What directories should be writable by the application? Adapt them by
giving writing permissions to the non-root users. Check Linux Wiki for more information
about changing permissions.
Debugging: You cannot perform any action that requires privileged permissions for
debugging purposes.
Note
Our sample application uses port 80 to listen for connections. Adapt it to use an alternative port such
as 8080:
Dockerfile:
...
COPY --from=builder /tiller-proxy /proxy
- EXPOSE 80
+ EXPOSE 8080
RUN useradd -r -u 1001 -g root nonroot
...
server.js:
...
const serverHost = '127.0.0.1';
- const serverPort = 80;
+ const serverPort = 8080;
...
On the other hand, the application writes its log in the /var/log/app.log file. Give permissions to the
nonroot user on that directory:
...
RUN useradd -r -u 1001 -g root nonroot
EXPOSE 80
+ RUN chmod -R g+rwX /var/log
VMware by Broadcom 33
VMware Tanzu Application Catalog Documentation - Tutorials
USER nonroot
...
Test it:
As you can see, everything is working as expected and now your container is not running as root
anymore.
Our application code is under the directory /app. Therefore, it makes sense to adapt the working
directory to it:
...
USER nonroot
+ WORKDIR /app
- CMD ["node", "/app/server.js"]
+ CMD ["node", "server.js"]
...
Note
Using the VOLUME instruction to create mount points is strongly recommended. Docker marks these
mount points as "holding externally mounted volumes", so the host or other containers know what
data is exposed.
Let's modify our application so the hostname and port are retrieved from a configuration file. Follow
these steps:
VMware by Broadcom 34
VMware Tanzu Application Catalog Documentation - Tutorials
...
// Constants
- const serverHost = '127.0.0.1';
- const serverPort = 8080;
+ const settings = require('/settings/settings.json');
+ const serverHost = settings.host;
+ const serverPort = settings.port;
...
...
EXPOSE 8080
+ VOLUME /settings
RUN useradd -r -u 1001 -g root nonroot
...
At this point, rebuild the image, and mount its configuration settings as shown below:
On distributions like Kubernetes, it is very common to have a logging system (such as ELK) that
collects logs from every container so they're available for the sysadmins. Making the logs available
for the host to collect is mandatory for these kinds of solutions.
Our application writes its log in the /var/log/app.log file. Redirect the logs to stdout using the
workaround below:
...
VOLUME /settings
+ RUN ln -sf /dev/stdout /var/log/app.log
RUN useradd -r -u 1001 -g root nonroot
...
With that change, execute the following commands to check that Docker correctly retrieved the
logs:
VMware by Broadcom 35
VMware Tanzu Application Catalog Documentation - Tutorials
Defining an entrypoint
To make the container more flexible, set an entrypoint to act as the main command of the image.
Then, use the CMD instruction to specify the arguments/flags of the command:
...
- CMD ["node", "server.js"]
+ ENTRYPOINT ["node"]
+ CMD ["server.js"]
This way, you can modify the container behavior depending on the arguments used to run it. For
instance, use the command below to maintain the original behavior:
You can always rewrite the entrypoint using the --entrypoint flag. For instance, to check the files
available at /app, run:
When an application requires initializing, use a script as your entrypoint. Find an example of the one
used on bitnami/redis image here.
It is considered bad security practice to store sensitive information, such as login credentials or API
tokens, as plaintext in a Dockerfile. A better approach, especially for containers that will run on
Kubernetes, is to encrypt this sensitive information in a Kubernetes SealedSecret. SealedSecrets can
be safely stored in public repositories and can only be decrypted by the Kubernetes controller
running in the target cluster.
VMware by Broadcom 36
VMware Tanzu Application Catalog Documentation - Tutorials
To demonstrate how to implement some changes on a given Dockerfile, I used an example with
several defects that would be corrected by applying these good practices. The initial Dockerfile had
the following issues:
It did not export any logs to the host, so sysadmins could not analyze them.
Upon implementing these minor adjustments, the resulting Dockerfile is ready to be used to build
containers for production environments.
Apart from these steps to write the best Dockerfiles for your production containers, here are few
more tips to be proficient at builiding containers.
Whenever a container is rebuilt, you should run a battery of validation, functional, and
integration tests for it. The more tests you perform, the better.
Rebuild your containers as frequently as possible (on a daily basis preferably) to ensure you
do not package old components in them.
Implement a CI/CD pipeline automating the building, testing, and publishing of container
images.
VMware by Broadcom 37
VMware Tanzu Application Catalog Documentation - Tutorials
Introduction
Three years have passed since the first release of Helm, and it has indeed made a name for itself.
Both avowed fans and fervent haters agree that the Kubernetes "apt-get equivalent" is the standard
way of deploying to production (at least for now, let's see what Operators end up bringing to the
table). During this time, Bitnami has contributed to the project in many ways. You can find us in PRs
in Helm's code, in solutions like Kubeapps, and especially in what we are mostly known for: our huge
application library.
<>
As maintainers of a collection of more than 45 Helm charts, we know that creating a maintainable,
secure and production-ready chart is far from trivial. In this sense, this blog post shows essential
features that any chart developer should know.
Note
In order to make your Helm chart work with non-root containers, add the securityContext section to
your yaml files.
This is what we do, for instance, in the Bitnami Elasticsearch Helm chart. This chart deploys several
Elasticsearch StatefulSets and Deployments (data, ingestion, coordinating and master nodes), all of
them with non-root containers. If we check the master node StatefulSet, we see the following:
spec:
{{- if .Values.securityContext.enabled }}
securityContext:
fsGroup: {{ .Values.securityContext.fsGroup }}
VMware by Broadcom 38
VMware Tanzu Application Catalog Documentation - Tutorials
{{- end }}
The snippet above changes the permissions of the mounted volumes, so the container user can
access them for read/write operations. In addition to this, inside the container definition, we see
another securityContext block:
{{- if .Values.securityContext.enabled }}
securityContext:
runAsUser: {{ .Values.securityContext.runAsUser }}
{{- end }}
In this part we specify the user running the container. In the values.yaml file, we set the default
values for these parameters:
With these changes, the chart will work as non-root in platforms like GKE, Minikube or Openshift.
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ template "rabbitmq.fullname" . }}-config
labels:
app: {{ template "rabbitmq.name" . }}
chart: {{ template "rabbitmq.chart" . }}
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
data:
enabled_plugins: |-
{{ template "rabbitmq.plugins" . }}
rabbitmq.conf: |-
##username and password
default_user={{.Values.rabbitmq.username}}
default_pass=CHANGEME
{{ .Values.rabbitmq.configuration | indent 4 }}
{{ .Values.rabbitmq.extraConfiguration | indent 4 }}
VMware by Broadcom 39
VMware Tanzu Application Catalog Documentation - Tutorials
Note that there is a section in the values.yaml file that allows you to include any custom
configuration:
This ConfigMap then gets mounted in the container filesystem, as shown in this extract of the
StatefulSet spec:
volumes:
- name: config-volume
configMap:
name: {{ template "rabbitmq.fullname" . }}-config
If the application needs to write in the configuration file, then you'll need to create a copy inside the
container, as ConfigMaps are mounted as read-only. This is done in the same spec:
containers:
- name: rabbitmq
image: {{ template "rabbitmq.image" . }}
imagePullPolicy: {{ .Values.image.pullPolicy | quote }}
command:
# ...
#copy the mounted configuration to both places
cp /opt/bitnami/rabbitmq/conf/* /opt/bitnami/rabbitmq/etc/rabbitmq
# ...
This will make your chart not only easy to upgrade, but also more adaptable to user needs, as they
can provide their custom configuration file.
VMware by Broadcom 40
VMware Tanzu Application Catalog Documentation - Tutorials
workloads.
When writing your chart, make sure that your deployment is able to work with the above tools
seamlessly. To do so, ensure the following:
All the containers log to stdout/stderr (so the EFK stack can easily ingest all the logging
information)
Prometheus exporters are included (either using sidecar containers or having a separate
deployment)
All Bitnami charts work with BKPR (which includes EFK and Prometheus) out of the box. Let's take a
look at the Bitnami PostgreSQL chart and Bitnami PostgreSQL container to see how we did it.
To begin with, the process inside the container runs at the foreground, so all the logging information
is written to stdout/stderr, as shown below:
With this, we ensured that it works with EFK. Then, in the chart we added a sidecar container for the
Prometheus metrics:
{{- if .Values.metrics.enabled }}
- name: metrics
image: {{ template "postgresql.metrics.image" . }}
imagePullPolicy: {{ .Values.metrics.image.pullPolicy | quote }}
{{- if .Values.metrics.securityContext.enabled }}
securityContext:
runAsUser: {{ .Values.metrics.securityContext.runAsUser }}
{{- end }}
env:
{{- $database := required "In order to enable metrics you need to specify
a database (.Values.postgresqlDatabase or .Values.global.postgresql.postgresqlDatabase
)" (include "postgresql.database" .) }}
- name: DATA_SOURCE_URI
value: {{ printf "127.0.0.1:%d/%s?sslmode=disable" (int (include "postgr
esql.port" .)) $database | quote }}
{{- if .Values.usePasswordFile }}
- name: DATA_SOURCE_PASS_FILE
value: "/opt/bitnami/postgresql/secrets/postgresql-password"
{{- else }}
- name: DATA_SOURCE_PASS
valueFrom:
secretKeyRef:
name: {{ template "postgresql.secretName" . }}
key: postgresql-password
{{- end }}
- name: DATA_SOURCE_USER
value: {{ template "postgresql.username" . }}
{{- if .Values.livenessProbe.enabled }}
livenessProbe:
httpGet:
path: /
VMware by Broadcom 41
VMware Tanzu Application Catalog Documentation - Tutorials
port: http-metrics
initialDelaySeconds: {{ .Values.metrics.livenessProbe.initialDelaySeconds
}}
periodSeconds: {{ .Values.metrics.livenessProbe.periodSeconds }}
timeoutSeconds: {{ .Values.metrics.livenessProbe.timeoutSeconds }}
successThreshold: {{ .Values.metrics.livenessProbe.successThreshold }}
failureThreshold: {{ .Values.metrics.livenessProbe.failureThreshold }}
{{- end }}
{{- if .Values.readinessProbe.enabled }}
readinessProbe:
httpGet:
path: /
port: http-metrics
initialDelaySeconds: {{ .Values.metrics.readinessProbe.initialDelaySeconds
}}
periodSeconds: {{ .Values.metrics.readinessProbe.periodSeconds }}
timeoutSeconds: {{ .Values.metrics.readinessProbe.timeoutSeconds }}
successThreshold: {{ .Values.metrics.readinessProbe.successThreshold }}
failureThreshold: {{ .Values.metrics.readinessProbe.failureThreshold }}
{{- end }}
volumeMounts:
{{- if .Values.usePasswordFile }}
- name: postgresql-password
mountPath: /opt/bitnami/postgresql/secrets/
{{- end }}
{{- if .Values.metrics.customMetrics }}
- name: custom-metrics
mountPath: /conf
readOnly: true
args: ["--extend.query-path", "/conf/custom-metrics.yaml"]
{{- end }}
ports:
- name: http-metrics
containerPort: 9187
{{- if .Values.metrics.resources }}
resources: {{- toYaml .Values.metrics.resources | nindent 12 }}
{{- end }}
{{- end }}
We also made sure that the pods or services contain the proper annotations that Prometheus uses to
detect exporters. In this case, we defined them in the chart's values.yaml file, as shown below:
metrics:
enabled: false
service:
type: ClusterIP
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9187"
#...
In the case of the PostgreSQL chart, these annotations go to a metrics service, separate from the
PostgreSQL service, which is defined as below:
{{- if .Values.metrics.enabled }}
apiVersion: v1
kind: Service
metadata:
VMware by Broadcom 42
VMware Tanzu Application Catalog Documentation - Tutorials
With these modifications, your chart will seamlessly integrate with your monitoring platform. All the
obtained metrics will be crucial for maintaining the deployment in good shape.
Useful Links
To learn more, check the following links:
VMware by Broadcom 43
VMware Tanzu Application Catalog Documentation - Tutorials
Introduction
Over the past few months, Bitnami have been working with non-root containers. We realized that
non-root images adds an extra layer of security to the containers. Therefore, we decided to release
a selected subset of our containers as non-root images so that our users could benefit from them.
In this blog post we see how a Bitnami non-root Dockerfile looks like by checking the Bitnami Nginx
Docker image. As an example of how the non-root containers can be used, we go through how to
deploy Ghost on Openshift. Finally, we will cover some of the issues we faced while moving all of
these containers to non-root containers
With a non-root container you can't do any of this . A non-root container should be configured for
its main purpose, for example, run the Nginx server.
Another reason for using non-root containers is because some Kubernetes distributions force you
to use them. For example Openshift, a Red Hat Kubernetes distribution. This platform runs
whichever container you want with a random UUID, so unless the Docker image is prepared to work
as a non-root user, it probably won't work due to permissions issues. The Bitnami Docker images
that have been migrated to non-root containers works out-of-the-box on Openshift.
FROM bitnami/minideb-extras:jessie-r22
VMware by Broadcom 44
VMware Tanzu Application Catalog Documentation - Tutorials
The BITNAMI_PKG_CHMOD env var is used to define file permissions for the folders where
we want to write, read or execute. The bitnami-pkg script reads this env var and performs
the changes.
The bitnami-pkg unpack nginx unpacks the Nginx files and changes the permissions as
stated by the BITNAMI_PKG_CHMOD env var.
Later, the USER 1001 directive switches the user from the default root to 1001. Although we
specify the user 1001, keep in mind that this is not a special user. It might just be whatever
UUID that doesn't match an existing user in the image. Moreover, Openshift ignores the
USER directive of the Dockerfile and launches the container with a random UUID.
Because of this, the non-root images cannot have configuration specific to the user running the
container. From this point to the end of the Dockerfile, everything is run by the 1001 user.
Finally, the entrypoint is in charge of configure Nginx. It is worth mentioning that no nginx,
www-data or similar user is created as the Nginx process will be running as the 1001 user.
Also, because we are running the Nginx service as an unprivileged user we cannot bind the
port 80, therefore we must configure the port 8080.
For simplicity we will use Minishift, a tool that helps you run OpenShift locally.
$ minishift start
$ eval $(minishift oc-env)
$ oc expose svc/ghost
$ oc status
VMware by Broadcom 45
VMware Tanzu Application Catalog Documentation - Tutorials
At this point, launch the Minishift dashboard with the following command, check the Ghost logs, and
access the application:
$ minishift dashboard
The logs from the Ghost container show that it has been successfully initialized:
Access to the Ghost application by clicking the service URL. You can find it in the top-right corner in
the first screenshot.
VMware by Broadcom 46
VMware Tanzu Application Catalog Documentation - Tutorials
I have no name!@a0e5d8399c5b:/$
Debugging experience
Troubleshooting problems on non-root containers can be challenging. Installing system packages
like a text editor or running network utilities is restricted due to insufficient permissions.
As a workaround, it is possible to edit the Dockerfile to install a system package. Or, we can start the
container as the root user using the --user root flag for Docker or the user: root directive for
docker-compose.
Mounted volumes
Additional challenges arise when you try to mount a folder from your host. Docker preserves UUID
and GUID from the host when mounting the host volume, potentially leading to permission issues
within the Docker volume. The user executing the container might lack the necessary privileges to
write to the volume.
Possible solutions are running the container with the same UUID and GUID as the host or change
the permissions of the host folder before mounting it to the container.
VMware by Broadcom 47
VMware Tanzu Application Catalog Documentation - Tutorials
Volumes in Kubernetes
Data persistence is configured using persistent volumes. Due to the fact that Kubernetes mounts
these volumes with the root user as the owner, the non-root containers don't have permissions to
write to the persistent directory.
Here are some steps we can take to address these permission issues:
Use an init-container to change the permissions of the volume before mounting it in the
non-root container. Example:
spec:
initContainers:
- name: volume-permissions
image: busybox
command: ['sh', '-c', 'chmod -R g+rwX /bitnami']
volumeMounts:
- mountPath: /bitnami
name: nginx-data
containers:
- image: bitnami/nginx:latest
name: nginx
volumeMounts:
- mountPath: /bitnami
name: nginx-data
Use Pod Security Policies to specify the user ID and the FSGroup that will own the pod
volumes. (Recommended)
spec:
securityContext:
runAsUser: 1001
fsGroup: 1001
containers:
- image: bitnami/nginx:latest
name: nginx
volumeMounts:
- mountPath: /bitnami
name: nginx-data
For example, in Git, running commands as an existing user was necessary until version 2.6.5+.
Otherwise, it triggers errors.
VMware by Broadcom 48
VMware Tanzu Application Catalog Documentation - Tutorials
Another example of a server facing this problem is Zookeeper. During the startup process,
Zookeeper encounters difficulty in determining the user name or user home. However, this issue is
non-disruptive, as Zookeeper operates flawlessly thereafter.
As we can see above, Zookeeper is unable to determine the user name or the user home.
For a hands-on exploration of the features and issues, check out one of the following Bitnami non-
root containers.
Also, if you are interested in non-root containers and Kubernetes security, I encourage you to take a
look at the following articles articles:
Non-Root Containers To Show Openshift Some Love Unprivileged Containers With Azure Container
Instances How to secure a Kubernetes cluster
VMware by Broadcom 49
VMware Tanzu Application Catalog Documentation - Tutorials
Introduction
There are two types of VMware Tanzu Application Catalog (Tanzu Application Catalog) container
images: root and non-root. Non-root images add an extra layer of security and are generally
recommended for production environments. However, because they run as a non-root user,
privileged tasks such as installing system packages, editing configuration files, creating system users
and groups, and modifying network information, are typically off-limits.
This guide gives you a quick introduction to non-root container images, explains possible issues you
might face using them, and also shows you how to modify them to work as root images.
Security: Non-root containers are automatically more secure. If there is a container engine
security issue, running the container as an unprivileged user will prevent any malicious code
from gaining elevated permissions on the container host. To learn more about Docker's
security features, see this guide.
Platform restrictions: Some Kubernetes distributions (such as OpenShift) run containers using
random UUIDs. This approach is not compatible with root containers, which must always run
with the root user's UUID. In such cases, root-only container images will simply not run and
a non-root image is a must.
Failed writes on mounted volumes: Docker mounts host volumes preserving the host UUID
and GUID. This can lead to permission conflicts with non-root containers, as the user running
the container may not have the appropriate privileges to write to the host volume.
Issues with specific utilities or services: Some utilities (eg. Git) or servers (eg. PostgreSQL)
run additional checks to find the user in the /etc/passwd file. These checks will fail for non-
root container images.
For Kubernetes, the chart uses an initContainer for changing the volume permissions
VMware by Broadcom 50
VMware Tanzu Application Catalog Documentation - Tutorials
properly.
For specific utilities, Tanzu Application Catalog ships the libnss-wrapper package, which
defines custom user space files to ensure the software acts correctly.
Useful links
To learn more about the topics discussed in this guide, consider visiting the following links:
VMware by Broadcom 51
VMware Tanzu Application Catalog Documentation - Tutorials
Introduction
As you probably already know, Docker containers typically run with root privileges by default. This
allows for unrestricted container management, which means you can do things like install system
packages, edit config files, bind privileged ports, etc. This is really useful for development purposes,
but can expose you to high risk once you put your containers into a production environment.
Why? Because anyone who accesses your container running as root can start undesirable processes
in it, such as injecting malicious code. And running a process in your container as root makes it
possible to change the user id (UID) or group id (GID) when starting the container, which makes your
application vulnerablehttps://www.projectatomic.io/blog/2016/01/how-to-run-a-more-secure-non-
root-user-container/v
Changing the configuration of your containers to make them run as non-root adds an extra layer
of security. Doing so limits the processes that can be executed and who can execute them. In our
quest to continually deliver the latest, most up-to-date and secure applications, Bitnami produces
and maintains a selection of non-root image containers - you can find them in our GitHub repository,
tagged as "non-root".
In this blog post, I will discuss root and non-root containers in more detail, exploring the difference
between the two and the benefits and disadvantages of each. I will also show you an example of how
Bitnami creates non-root containers by editing its Dockerfile to change its user permissions and
environment variables.
But containers don't need to be run as root user. Moreover, applications, databases, load balancers,
VMware by Broadcom 52
VMware Tanzu Application Catalog Documentation - Tutorials
Why not provide your containers with security from the beginning, by running them as non-root
user?
Following the Principle of Least Privilege (PoLP), the main difference between root and non-root
containers is that the latter are focused on ensuring the minimum amount of privileges necessary to
run a process.
To modify the container system, allowing the user to do things like edit the host filesystem,
install system packages at runtime, etc.
Meanwhile, non-root containers regulate which users in which namespaces are able to execute
specific processes, what volumes can be accessed, and what ports your container is allowed to
access.
"Would I run any process or application as root in my server?" The answer, of course, would be no,
right? So why would you do so in your containers?
Running your containers as non-root prevents malicious code from gaining permissions in the
container host and means that not just anyone who has pulled your container from the Docker Hub
can gain access to everything on your server, for example. If your container gives users privileges,
then anyone could run undesired processes, change the UIDs, or gain access to secrets, etc. You
will also probably want to work with non-root containers in a multi-tenant Kubernetes cluster for
enforcing security.
While security is the foremost advantage of non-root containers, there are others.
Root-only containers simply do not run in that distro. So running non-root containers enables you to
use Kubernetes distributions like Openshift. For more information on this, check out the following
post about Running Non-Root Containers on Openshift.
VMware by Broadcom 53
VMware Tanzu Application Catalog Documentation - Tutorials
These are some of the Docker containers that Bitnami has released as non-root:
Nginx Kafka Zookeeper Memcached Node Exporter Prometheus Alert Manager Blackbox Exporter
PHP-FPM Redis Ghost MariaDB
But there are many more Bitnami containers available with non-root privileges. To view all of them,
take a look at those tagged as non-root in the Bitnami GitHub repository
Let me now explain what tweaks Bitnami made to transform a root container into a non-root
container. To do so, I will use the Bitnami Redis Docker image.
The image above shows three lines highlighted; I am going to explain the meaning and behavior of
each:
The BITNAMI_PKG_CHMOD env var defines the file permissions for the folders: write, read or
execute.
The ../libcomponen.sh && component_unpack "redis" script is used for unpacking the
Redis files and changing the permissions as stated in the BITNAMI_PKG_CHMOD env var.
At this point, everything has been executed as root user at build time of the container. But the last
highlighted line indicates that the default user must be changed from root to 1001:
USER 1001: this is a non-root user UID, and here it is assigned to the image in order to run
the current container as an unprivileged user. By doing so, the added security and other
restrictions mentioned above are applied to the container.
Basically, it has been introduced an environment variable to set the file permissions and specify a
user, in order to avoid running the container as root in its Dockerfile. That way, any time you run the
container, it will already have the "instructions" to run as non-root user.
This is only one of the many ways to secure your containers. I encourage you to research other ways
VMware by Broadcom 54
VMware Tanzu Application Catalog Documentation - Tutorials
to turn your Docker images into non-root containers, or to take advantage of the ready-to-run non-
root containers already available from Bitnami.
Useful links
If you want to learn more about non-root containers and Docker and Kubernetes security, check out
the following articles:
Docker Security documentation Work with non-root containers for Bitnami applications Running
non-root containers on Openshift Bitnami How-to guides for containers Understanding how uid and
gid work in Docker containers by Marc Campbell Processes In Containers Should Not Run As Root
Just say no to root (containers) by Daniel J. Walsh Running a Docker container as a non-root user by
Lucas Willson-Richter How to run a more secure non-root user container by Dan Wash
VMware by Broadcom 55
VMware Tanzu Application Catalog Documentation - Tutorials
Introduction
For developers building cloud-native applications and APIs for Kubernetes, VMware Tanzu
Application Catalog (Tanzu Application Catalog) offers a variety of containers and Helm charts to ease
the process. These ready-to-use assets make it easier to develop and deploy applications
consistently, follow best practices and focus on code rather than infrastructure configuration. Tanzu
Application Catalog containers and charts are also always secure, optimized and up-to-date, so you
can rest assured that your applications always have access to the latest language features and
security fixes.
To illustrate these benefits, this tutorial will walk you through the process of developing and
deploying a sample Node.js REST API locally using Tanzu Application Catalog containers. You will
create and run a sample REST API locally on your development system using the Sails framework.
You will also create a local MongoDB service for API data storage, and integrate and test your REST
API with this MongoDB service. To perform these tasks, you can either use your existing Node.js
development environment or, if you don't have one, you can use the following Tanzu Application
Catalog container images:
Tanzu Application Catalog's Node.js container image contains the Node.js runtime together
with all required dependencies and development tools.
Tanzu Application Catalog's MongoDB container image contains the official MongoDB
Community binaries together with support for persistence, SSL and replica sets.
You have Docker installed and configured. Learn more about installing Docker.
You have a basic understanding of Node.js and REST API concepts. Learn more about
Node.js and REST.
VMware by Broadcom 56
VMware Tanzu Application Catalog Documentation - Tutorials
1. Begin by creating a directory for your application and making it the current working
directory:
mkdir myapp
cd myapp
2. Use the following Docker commands to create and start a Tanzu Application Catalog Node.js
container on your host (replace the REGISTRY placeholder with your Tanzu Application
Catalog container registry):
The -v argument to the first command tells Docker to mount the host's current directory into
the container's /app path, so that the effects of commands run in the container are seen on
the host. The --net="host" parameter tells Docker to use the host's network stack for the
container. The container is named node.
Once the container is running, connect to the container console with the command below.
This will give you a command shell and allow you to use the Node.js tools available in the
image for subsequent tasks.
3. Install Sails and then use the Sails CLI to create the scaffolding for a skeleton application.
When prompted for the application type, choose an "Empty" application.
Once the application scaffolding has been generated, start the application:
sails lift
4. By default, a Sails application starts in development mode and runs at port 1337. Browse to
http://:1337, where DOCKER-HOST-ADDRESS is the IP address of your host, and confirm
that you see the Sails welcome page shown below:
VMware by Broadcom 57
VMware Tanzu Application Catalog Documentation - Tutorials
5. Exit the container console. This will terminate the Sails application process, although the
container will continue to run in the background.
Create and start a MongoDB database service using the Tanzu Application Catalog MongoDB
container on your host. If you wish, you can replace the database credentials and other variables
shown below with your own values, but make a note of them as you will need them in the next step.
Replace the REGISTRY placeholder with a reference to your Tanzu Application Catalog container
registry.
The environment variables passed to the first command set the administrator password for the
MongoDB instance and also create a new database named mydb with corresponding user credentials.
This database will be used to store data for the REST API. As before, the --net="host" parameter
tells Docker to use the host's network stack for this container as well. The container is named
mongodb and, once started, the MongoDB service will be available on the Docker host at port 27017.
VMware by Broadcom 58
VMware Tanzu Application Catalog Documentation - Tutorials
2. Sails comes with a built-in generator for API endpoints. Use this to generate the scaffolding
for a new sample REST API endpoint for Item objects. By default, this endpoint will be
exposed at the /item URI.
4. Follow the steps outlined in the Sails documentation to configure the generated application
to use MongoDB for data storage. First, edit the myapp/config/datastores.js file and modify
the default datastore entry as shown below.
default: {
adapter: 'sails-mongo',
url: 'mongodb://myapp:myapp@localhost/mydb'
}
If you used different values when creating the MongoDB container, or if you're using a
different MongoDB installation, remember to replace the values shown above as needed.
migrate: 'alter',
id: { type: 'string', columnName: '_id' },
5. Create a data model for the REST API Item object. For this article, use a simple model with
just two attributes: a name and a quantity. Edit the myapp/api/models/Item.js and update it
to look like this:
module.exports = {
attributes: {
name: 'string',
quantity: 'number'
}
};
6. Connect to the container console again. Start the application and put it in the background:
As before, the application will start in development mode and become available at port 1337 of the
host.
VMware by Broadcom 59
VMware Tanzu Application Catalog Documentation - Tutorials
1. At the host console, send a POST request to the API using curl to create a new item record:
curl http://localhost:1337/item
You can also connect to the running MongoDB container and use the mongo CLI to see the
data in the MongoDB database.
VMware by Broadcom 60
VMware Tanzu Application Catalog Documentation - Tutorials
3. Modify the item record with a PUT request. Replace the ID placeholder in the command
below with the document's unique identifier from the previous commands.
You can also connect to the running MongoDB container and use the mongo CLI to confirm
that the data has been deleted from the MongoDB database:
VMware by Broadcom 61
VMware Tanzu Application Catalog Documentation - Tutorials
At this point, you have a working Node.js REST API integrated with a MongoDB database.
Useful links
To learn more about the topics discussed in this article, use the links below:
Sails documentation
MongoDB documentation
VMware by Broadcom 62
VMware Tanzu Application Catalog Documentation - Tutorials
Introduction
This guide walks you through the process of running an example Go application on a Kubernetes
cluster. It uses a simple API for a "to-do list" application. The first step is to create the Go program
binary, insert the binary into a minimal Dockerfile and use it as a starting point for creating a custom
Helm chart to automate the application deployment in a Kubernetes cluster. Once the application is
deployed and working, it also explores how to modify the source code for publishing a new
application release and how to perform rolling updates in Kubernetes using the Helm CLI.
Go features
Go applications are generally suitable for running in containers because they can be compiled as a
single binary that contains all the dependencies they need to run. The compiled binary can run
without the Go runtime, so container images are smaller.
You have basic knowledge of the Go programming language and have run Go applications
before.
You have basic knowledge of Helm charts and how to create them.
You have an account in a container registry (this tutorial assumes that you are using Docker
Hub).
To create your own application in Go and deploy it on Kubernetes using Helm you will typically follow
these steps:
VMware by Broadcom 63
VMware Tanzu Application Catalog Documentation - Tutorials
This will clone the entire tutorials repository. In this repository you will find the following:
Dockerfile: a text file that contains instructions on how to build a Docker image. Each line
indicates an instruction and a command for assembling all the pieces that comprise the
image.
app-code directory: a folder that contains the application source code and a pre-built binary.
helm-chart directory: a folder that contains the ready-made Helm chart used in this tutorial.
This tutorial skips the step of creating a Go binary, as it is out of the scope of the current guide. It
uses the existing Go binary that is in the app-code directory in the project code repository. Check
the official Go documentation for further information on how to build a Go binary.
Note
The following steps only apply if you already have a Go binary. If you don't, skip
them and build the Docker image as shown in Step 2.
If you have Go already installed, you can simply build it with the following command:
There are different ways to build a binary with Go. Using the -tags netgo option prevents the net
package from linking to the host resolver, ensuring that the binary is not linked to any system library.
This is good for containers because we can deploy a very minimal image without any required
libraries (for example, the Docker "scratch" image).
Some of the cons of this approach would be that you have to include other files for Web
applications, like CA certificates, or if you want to use a shell. For these reasons, this tutorial deploys
the Go web application on top of Bitnami's minideb image, which is a minimal version of Debian
designed for use in containers.
cp http-sample tutorials/go-k8s/app-code/
VMware by Broadcom 64
VMware Tanzu Application Catalog Documentation - Tutorials
Once you have completed the steps above, running a Go application is very easy. You only need to
add the binary to a Docker image. Check the Dockerfile you will find in the next step to see how
simple this is.
You will see output like this during the build process:
VMware by Broadcom 65
VMware Tanzu Application Catalog Documentation - Tutorials
docker login
Push the image to your Docker Hub account. Replace the DOCKER_USERNAME
placeholder with the username of your Docker Hub account and my-custom-app:latest with
the name and the version of your Docker image:
Confirm that you see the image in your Docker Hub repositories dashboard.
If you examine the repository you just downloaded, there is a directory named helm-chart that
already contains the files you need. Check out the chart's file structure:
go-k8s
|-- Chart.yaml
|-- charts
|-- templates
| |-- NOTES.txt
| |-- _helpers.tpl
| |-- deployment.yaml
| |-- ingress.yaml
| `-- service.yaml
`-- values.yaml
VMware by Broadcom 66
VMware Tanzu Application Catalog Documentation - Tutorials
Note
Before performing the following steps, make sure you have a Kubernetes cluster
running with Helm v3.x installed. For detailed instructions, refer to our starter tutorial.
At this point, you have built a Docker image, published it in a container registry and created your
custom Helm chart. It's now time to deploy the example Go application to the Kubernetes cluster. To
deploy the example application using the current Helm chart, follow these steps:
Make sure that you can connect to your Kubernetes cluster by executing the command
below:
kubectl cluster-info
VMware by Broadcom 67
VMware Tanzu Application Catalog Documentation - Tutorials
Once the chart has been installed, you will see a lot of useful information about the deployment. The
application won't be available until database configuration is complete. Follow these instructions to
check the database status:
Run the kubectl get pods command to get a list of running pods:
Once you've configured the database, you can access the application. To obtain the application URL,
run the commands shown in the "Notes" section below.
If you're using Minikube, you can also check the application service to get the application's URL. You
have two ways to do this:
Option 1: List the services by executing the minikube service list command. You'll notice two
service names:
VMware by Broadcom 68
VMware Tanzu Application Catalog Documentation - Tutorials
Option 2: Check the application service using the minikube service SERVICE command
(SERVICE is a placeholder. Remember to replace it with the name of the service you want to
check):
Build the new image and tag it as 0.2.0. Remember to replace the USERNAME placeholder
with your Docker ID in the following steps.
Note
Before performing the next step, make sure that you are logged into Docker
Hub. Run the docker login command to access your account (if applicable).
Publish the newimage following the same steps as in Step 3 but using the new version
number.
Change to the helm-chart/go-k8s/ directory, where you have the Helm chart files. Edit the
VMware by Broadcom 69
VMware Tanzu Application Catalog Documentation - Tutorials
values.yaml file to replace the current image tag with the new one:
Run the helm upgrade command followed by the name of the chart. After that, you will see
the information about the new deployment. RELEASE-NAME is a placeholder, replace it with
the right value:
See what revisions have been made to the chart by executing the helm history command:
Follow these steps every time you want to update your Docker image and Helm chart.
Useful links
To learn more about the topics discussed in this guide, use the links below:
Go official documentation
Bitnami GitHub
Minikube
Kubernetes
VMware by Broadcom 70
VMware Tanzu Application Catalog Documentation - Tutorials
Introduction
Kubernetes, like any other secure system, supports the following concepts:
Authentication: Verifying and proving identities for users and groups, and service accounts
Authorization - the process of handling users' access to resources - is always a challenge, especially
when access is to be controlled by either team membership or project membership. Two key
challenges are:
As Kubernetes group membership is handled externally to the API itself by an Identity Provider
(IdP), the cluster administrator needs to interact with the Identity Provider administrator to setup
those group memberships, making the workflow potentially cumbersome.Identity Providers may not
provide group membership at all, forcing the cluster administrator to handle access on a per-user
basis, i.e. Kubernetes RoleBindings containing the "full" list of allowed end-users.
In this tutorial, we propose a way to "mimic" group memberships - which can be either by team,
project or any other aggregation you may need - using stock Kubernetes authorization features.
Have some knowledge and experience with RBAC roles and bindings
Configure your clusters with Kubernetes RBAC enabled, default since 1.6 release
Here is a quick recap on how Kubernetes approaches authentication. There are two main categories
of users:
ServiceAccounts (SAs):
VMware by Broadcom 71
VMware Tanzu Application Catalog Documentation - Tutorials
The ID is externally provided, usually by the IdP. There are many mechanisms to
provide this ID, such as:
x509 certs
Webhook tokens
Managed Kubernetes providers (e.g. GKE, AKS, EKS) integrated with their
own Cloud authentication mechanisms
The user ID is included in every call to the Kubernetes API, which in turn is authorized by access
control mechanisms.
It's common to adopt OIDC for authentication as it provides a Single-Sign-On (SSO) experience,
although some organizations may still use end-users x509 certs as these can be issued without any
external IdP intervention. However, these common approaches present the following challenges:
x509 certs: Although they may be easy to setup, users end up owning an x509 bundle (key
and certificate) that cannot be revoked. This forces the cluster owner to specify low
expiration times, obviously depending on staff mobility. Additionally, the user's Group is
written into the x509 certificate itself. This forces the cluster administrator to re-issue the
certificate every time the user changes membership, while being unable to revoke the
previous certificate (i.e. the user will continue to remain a member of older groups until the
previous certificate expires).
OIDC authentication: This method is convenient to provide SSO using the IdP in use by the
organization. The challenge here arises when the provided identity lacks group membership,
or group membership (as setup by the organization) doesn't directly map to users' team or
project memberships regarding their Kubernetes workloads needs.
With the user now authenticated, we need to take a look at how we authorize them to use the
Kubernetes Cluster.
In the above model, B) is implemented as a Kubernetes Role (or ClusterRole), while A) → B) binding
is modeled as a Kubernetes RoleBinding (or ClusterRoleBinding), as per below example diagram:
VMware by Broadcom 72
VMware Tanzu Application Catalog Documentation - Tutorials
As these acquired identities do not necessarily need to exist - recall that the Kubernetes control
plane itself doesn't have a Users or Groups store - we will call them "virtual-users" in this article. This
feature enables setting up “virtual-users” as “role accounts” security Principals. For example:
RBAC rules can be created to allow such "virtual-users" to access the Kubernetes resources they
need, as per below diagram:
As shown above, using stock Kubernetes RBAC features, authorization handling is divided into:
team membership: RBAC ClusterRoles and ClusterroleBindings that state Users who are
allowed to impersonate their team's virtual-user.
team duties: RBAC Roles and RoleBindings that state which actual Kubernetes resources the
team's virtual-user can access.
VMware by Broadcom 73
VMware Tanzu Application Catalog Documentation - Tutorials
The actual impersonate action is specified via headers in the Kubernetes API call, which is
conveniently implemented by kubectl via:
Note
kubectl --as-group … without the --as parameter is not valid. To simplify the CLI
usage, this article proposes using the first form above, by modeling the user-to-
impersonate as a "virtual-user" representing the user group or team memberships.
Following the example shown in the previous diagram, the User "[email protected]" can easily
impersonate virtual team-user "app-fe-user" by overloading kubectl CLI using the command below:
The Kubernetes cluster has three namespaces (NS) relevant to app-fe workloads:
development, staging, and production.
A virtual-user named app-fe-user will be created, allowing Alice and Alanis to impersonate it.
Note
For the sake of simplicity, we will use stock Kubernetes ClusterRoles (usable for
namespace scoped RoleBindings) to implement the above access rules.
The example below implements the idea, using k14s/ytt as the templating language (you can find
below the ytt source code and resulting manifested YAML here):
#@ load("impersonate.lib.yml",
#@ "ImpersonateCRBinding", "ImpersonateCRole", "RoleBinding"
VMware by Broadcom 74
VMware Tanzu Application Catalog Documentation - Tutorials
#@ )
https://github.com/k14s/ytt
#@ members = ["[email protected]", "[email protected]"]
#@ prod_namespace = "prod-app-fe"
#@ stag_namespace = "staging-app-fe"
#@ dev_namespace = "dev-app-fe"
#@ team_user = "app-fe-user"
The resulting YAML output can be pushed via kubectl as usual executing the following command:
Note
After pushing above RBAC resources to the cluster, alice@example can use the kubectl auth can-i ...
command to verify the setup. For example:
To have the configuration pre-set for impersonation, there are some not-so extensively documented
fields that can be added to the "user:" entry in the user's KUBECONFIG file:
- name: [email protected]@CLUSTER
user:
as: app-fe-user
auth-provider:
config:
client-id: <...>.apps.googleusercontent.com
client-secret: <...>
VMware by Broadcom 75
VMware Tanzu Application Catalog Documentation - Tutorials
require other Kubernetes tools to support impersonation, e.g. helm is a notable example
lacking this feature
Audit trails
Kubernetes impersonation is well designed regarding audit trails, as API calls get logged with full
original identity (user) and impersonated user (impersonatedUser). The following code block shows
how to configure a kube-audit log trace from kubectl --as app-fe-user get pod -n dev-app-fe:
{
"kind": "Event",
"apiVersion": "audit.k8s.io/v1",
"level": "Request",
"auditID": "032beea1-8a58-434e-acc0-1d3a0a98b108",
"stage": "ResponseComplete",
"requestURI": "/api/v1/namespaces/dev-app-fe/pods?limit=500",
"verb": "list",
"user": {
"username": "[email protected]",
"groups": ["system:authenticated"]
},
"impersonatedUser": {
"username": "app-fe-user",
"groups": ["system:authenticated"]
},
"sourceIPs": ["10.x.x.x"],
"userAgent": "kubectl/v1.18.6 (linux/amd64) kubernetes/dff82dc",
"objectRef": {
"resource": "pods",
"namespace": "dev-app-fe",
"apiVersion": "v1"
},
"responseStatus": {
"metadata": {},
"code": 200
},
"requestReceivedTimestamp": "2020-07-24T21:25:50.156032Z",
"stageTimestamp": "2020-07-24T21:25:50.161565Z",
"annotations": {
"authorization.k8s.io/decision": "allow",
"authorization.k8s.io/reason": "RBAC: allowed by RoleBinding \"rb-app-fe-user-admi
n\" of ClusterRole \"admin\" to User \"app-fe-user\""
VMware by Broadcom 76
VMware Tanzu Application Catalog Documentation - Tutorials
}
}
Picky readers will also note that the "user" field above has only "username" relevant to the User
identity, as "system:authenticated" is obviously a generic group value.
Conclusion
By using stock Kubernetes RBAC features, a cluster administrator can create virtual user security
Principals which are impersonated by Persona Users, to model "role-account" authorization
schemes. This approach provides numerous benefits related to the Kubernetes security
configuration, as follows:
It requires the authentication mechanism to only provide User identity data (i.e. no Group
needed).
It allows the Kubernetes cluster administrator to build team membership schemes using the
stock Kubernetes RBAC impersonate feature.
It allows the Kubernetes cluster administrator to create RBAC rules to access Kubernetes
Resources against these impersonated "virtual-users" (Kubernetes Rolebinding "subjects",
usually just a single entry).
It decouples membership from actual resource access rules which allows creating cleaner
RBAC entries. Such entries are easier to maintain and audit, reducing complexity and
workload for cluster administrators.
It benefits the Organization as the cluster administrator can more precisely implement team
and project controls, easing staff on/off boarding and related security aspects.
Useful links
RBAC, from wikipedia
Kubernetes authentication
Kubernetes RBAC
VMware by Broadcom 77
VMware Tanzu Application Catalog Documentation - Tutorials
Introduction
When you install an application in a Kubernetes cluster, the Kubernetes scheduler decides in which
nodes the application pods will be installed unless certain constraints are defined. For example,
Kubernetes scheduler may decide to install application pods in a node with more available memory.
This is mostly useful except when cluster administrators prefer to distribute a group of pods across
the cluster in a specific manner. For this use case, they need a tool that can force Kubernetes to
follow custom rules specified by the user.
Affinity rules supply a way to force the scheduler to follow specific rules that determine where pods
should be distributed. To help users to implement affinity rules, Bitnami has enhanced its Helm
charts by including opinionated affinities in their manifest files. Cluster administrators now only need
to define the criteria to be followed by the scheduler when placing application pods in cluster nodes.
They can then enable this feature via a simple install-time parameter
This tutorial will demonstrate the available affinity rules and how they can be adapted to your needs.
Note
This guide uses a Kubernetes cluster created in GKE. These steps are the same for
all Kubernetes engines. They don't work, however, in Minikube, since with Minikube
you only can create single-node clusters.
You have a Google Cloud account. To register, see Google Cloud account.
You have a Kubernetes cluster running with Helm v3.x and kubectl installed. To learn more,
see Getting started with Kubernetes and Helm using different cloud providers.
VMware by Broadcom 78
VMware Tanzu Application Catalog Documentation - Tutorials
Pod affinity and anti-affinity rules enable you to define how the scheduler should operate when
locating application pods in your cluster's eligible nodes. Based on the option you select, the
scheduler will operate in the following manner.
podAffinityPreset: Using the podAffinity rule, the scheduler will locate a new pod on the
same node where other pods with the same label are located. This approach is especially
helpful to group under the same node pods that meet specific pre-defined patterns.
podAntiAffinitypreset: Using the podAntiAffinity parameter lets the scheduler locates one
pod in each node. Thus, you will prevent locating a new pod on the same node as other
pods are running. This option is convenient if your deployment will demand high availability.
Distributing the pods across all nodes enables Kubernetes to maintain high availability in your cluster
by keeping the remaining nodes running in the event of one node failure.
These are the values you can set for both pod affinity and anti-affinity rules:
Soft: Use this value to make the scheduler enforce a rule wherever it can be met (best-effort
approach). If the rule cannot be met, the scheduler will deploy the required pods in the
nodes with enough resources.
Hard: Use this value to make the scheduler enforce a rule. This means that if there are
remaining pods that do not comply with the pre-defined rule, they won't be allocated in any
node.
Bitnami Helm charts have the podAntiAffinity rule with the soft value enabled by default. Hence, if
there are not enough nodes to place one pod per node, it will leave the scheduler to decide where
the remaining pods should be located.
The following section shows two different use cases of configuring podAntiaffinity parameter.
Use case 1: Install the chart with the default podAntiaffinity value
Install the Bitnami Helm charts repository by running:
Deploy the MySQL Helm chart by executing the command below. Note that the chart will
deploy the cluster with three nodes and two replicas - one primary and one secondary.
VMware by Broadcom 79
VMware Tanzu Application Catalog Documentation - Tutorials
To make the scheduler follow the default podAntiAffinity rule, set the parameter as follows:
* Verify the cluster by checking the nodes. To list the connected nodes, execute:
```bash
kubectl get nodes
As expected, both the primary and the secondary pods are in different nodes.
To verify how the scheduler acts when the soft value is defined, scale up the cluster by setting the
number of secondary replicas to three instead of one. Thus, the resulting number of pods will be
four, instead of two.
Check the pods by running again the kubectl get pods command. The soft value left the
scheduler to locate the remaining pod that didn't comply with the "one-pod-per-node" rule:
To try the hard type of the podAntiAffinity rule, deploy the chart again by changing the
secondary.podAntiAffinityPreset value from soft to hard as shown below. The chart will deploy the
cluster with three nodes and two replicas - one primary and one secondary.
VMware by Broadcom 80
VMware Tanzu Application Catalog Documentation - Tutorials
Check the nodes and the pods by running the kubectl get nodes and the kubectl get pods –
o wide commands:
Both the primary and secondary pods are running in the same node.
To verify how the scheduler acts when the hard value is defined, scale up the cluster by
setting the number of secondary replicas to three instead of one. Thus, the resulting number
of pods will be four, instead of two.
When checking the pods, you will see that the scheduler has ignored the "one-pod-per-node" rule
and also located only as many pods as there are nodes. The fourth pod was not deployed as there
are only three nodes available.
The podAntiAffinity rule is an easy way to control how application pods will be distributed across the
cluster nodes when installing a Helm chart. Deploy your favorite Bitnami applications and enable this
feature via a simple install-time parameter.
Useful links
To learn more about the topics discussed in this article, use the links below:
VMware by Broadcom 81
VMware Tanzu Application Catalog Documentation - Tutorials
Introduction
Helm v3 was released a few months ago, bringing with a number of architectural changes and new
features - most notably, the removal of Tiller and an improved upgrade process. To make it easier
for users to transfer their Helm v2 releases to Helm v3, the Helm maintainers also released a plugin
that takes care of migration tasks automatically.
After migrating your releases to Helm v3, you might come across some cases where subsequent
upgrades fail - for example, when an upgrade attempts to modify an immutable field in a StatefulSet.
In these situations, you can attempt to resolve the issue using one of the following methods:
Back up the data from the migrated release and restore it in a new release using the
application's built-in backup/restore tools.
Back up the persistent volumes from the migrated release and re-deploy them in a new
release using Velero, a Kubernetes backup/restore tool.
You have a Kubernetes cluster with kubectl and Helm v3 installed. This guide uses a Google
Kubernetes Engine (GKE) cluster but you can also use any other Kubernetes provider. Learn
about deploying a Kubernetes cluster on different cloud platforms and how to install kubectl
and Helm.
You have previously deployed a Bitnami Helm chart using Helm v2, added data to it and then
migrated it to Helm v3 using the Helm migration plugin. Example command sequences to
perform these tasks are shown below, where the PASSWORD and REPL-PASSWORD
placeholders refer to the database and replication user passwords respectively.
VMware by Broadcom 82
VMware Tanzu Application Catalog Documentation - Tutorials
Note
Throughout this guide, helm2 refers to the Helm v2 CLI and helm3 refers to the Helm v3 CLI.
Back up the contents of all the databases to a file using the PostgreSQL pg_dumpall tool. If
this tool is not installed on your system, use Bitnami's PostgreSQL Docker container image,
which contains this and other PostgreSQL client tools, to perform the backup, as shown
below:
Here, the --net parameter lets the Docker container use the host's network stack and
thereby gain access to the forwarded port. The pg_dumpall command connects to the
PostgreSQL service and creates an SQL output file containing all the database structures and
records in the PostgreSQL cluster. Finally, the --rm parameter deletes the container after the
pg_dumpall command completes execution.
At the end of this step, you should have a backup file containing the data from your running
PostgreSQL release.
VMware by Broadcom 83
VMware Tanzu Application Catalog Documentation - Tutorials
The next step is to create an empty PostgreSQL cluster and restore the data into it:
Create a new PostgreSQL release in a separate namespace using Helm v3. Replace the
PASSWORD and REPL-PASSWORD placeholders with the database and replication user
passwords respectively.
Note
It is important to create the new release using the same credentials as the
original release to avoid authentication problems.
Create an environment variable with the password for the new release:
Restore the contents of the backup file into the new release using the psql tool. If this tool is
not available on your system, mount the directory containing the backup file as a volume in
Bitnami's PostgreSQL Docker container and use the psql client tool in the container image to
import the backup file's contents into the new cluster, as shown below:
Here, the -v parameter mounts the current directory (containing the backup file) to the
container's /app path. Then, the psql client tool is used to connect to the PostgreSQL service
and execute the SQL commands in the backup file, thereby restoring the data from the
original deployment. As before, the --rm parameter destroys the container after the
command completes execution.
Connect to the new deployment and confirm that your data has been successfully restored:
VMware by Broadcom 84
VMware Tanzu Application Catalog Documentation - Tutorials
Note
When upgrading the release, use the same parameters as when you installed it.
After confirming that all is in order, you can optionally delete your original release.
Follow the Velero plugin setup instructions for your cloud provider. For example, if you are
using Google Cloud Platform (as this guide does), follow the GCP plugin setup instructions to
create a service account and storage bucket and obtain a credentials file.
Then, install Velero by executing the command below, remembering to replace the
BUCKET-NAME placeholder with the name of your storage bucket and the SECRET-
FILENAME placeholder with the path to your credentials file:
You should see output similar to the screenshot below as Velero is installed:
VMware by Broadcom 85
VMware Tanzu Application Catalog Documentation - Tutorials
Confirm that the Velero deployment is successful by checking for a running pod using the
command below:
Create a backup of the volumes in the running PostgreSQL deployment. This backup will
contain both the master and slave volumes.
To view the contents of the backup and confirm that it contains all the required resources,
execute:
To avoid the backup data being overwritten, switch the bucket to read-only access:
Restore the persistent volumes in a separate namespace using Velero. The --namespace-
mappings parameter allows you to map resources from the original namespace to the new
one.
VMware by Broadcom 86
VMware Tanzu Application Catalog Documentation - Tutorials
ew
Confirm that the persistent volumes have been restored in the target namespace and note
the volume name for the master database node:
Delete the persistent volume corresponding to the slave node and retain only the volume
corresponding to the master node. If there is more than one slave volume (depending on
how you originally deployed the chart), delete all the slave volumes.
Create a new PostgreSQL release in the target namespace using Helm v3. Use the chart's
persistence.existingClaim parameter to create a release with an existing volume instead of a
fresh one. Replace the PASSWORD and REPL-PASSWORD placeholders with the same
database and replication user passwords used in the original release, and the MASTER-PVC-
NAME placeholder with the name of the restored master node volume.
Note
It is important to create the new release using the same credentials as the
original release to avoid authentication problems.
This will create a new release that uses the original master volume (and hence the original
data). Note that if replication is enabled, as in the example above, installing the chart will
automatically create a new slave volume for each slave node.
Connect to the new deployment and confirm that your original data is intact:
VMware by Broadcom 87
VMware Tanzu Application Catalog Documentation - Tutorials
Note
When upgrading the release, use the same parameters as when you installed it.
After confirming that all is in order, you can optionally delete your original release.
Useful links
Bitnami PostgreSQL Helm chart
Velero documentation
VMware by Broadcom 88
VMware Tanzu Application Catalog Documentation - Tutorials
Introduction
Kubernetes is the recommended way to manage containers in production. To make it even easier to
work with Kubernetes, Bitnami offers:
In many cases, though, you might find that your Bitnami application has not been correctly deployed
to your Kubernetes cluster, or that it is not behaving the way it should. This guide provides some
broad troubleshooting ideas and solutions to common problems you might encounter with your
Kubernetes cluster.
How to detect
Kubernetes issues are not always very easy to detect. In some cases, errors are obvious and can be
resolved easily; in others, you might find that your deployed application is not responding, but
detecting the error requires you to dig deeper and run various commands to identify what went
wrong.
Typically, running kubectl get pods gives you a top-level overview of whether pods are running
correctly, or which pods have issues. You can then use kubectl describe and kubectl logs to obtain
more detailed information.
Common issues
The following are the most common issues that Bitnami users face:
VMware by Broadcom 89
VMware Tanzu Application Catalog Documentation - Tutorials
Authentication failures
Troubleshooting checklist
The following checklist covers the majority of the cases described above and will help you to find and
debug most Kubernetes deployment issues.
If kubectl get pods shows that your pod status is Pending or CrashLoopBackOff, this means that the
pod could not be scheduled on a node. Typically, this is because of insufficient CPU or memory
resources. It could also arise due to the absence of a network overlay or a volume provider. To
confirm the cause, note the pod identifier from the previous command and then run the command
below, replacing the POD-UID placeholder with the correct identifier:
The output of the command should provide information about why the pod is pending. Here's an
example:
VMware by Broadcom 90
VMware Tanzu Application Catalog Documentation - Tutorials
If available resources are insufficient, try freeing up existing cluster resources or adding more nodes
to the cluster to increase the available cluster resources.
If kubectl get pods shows that your pod status is ImagePullBackOff or ErrImagePull, this means that
the pod could not run because it could not pull the image. To confirm this, note the pod identifier
from the previous command and then run the command below, replacing the POD-UID placeholder
with the correct identifier:
The output of the command should provide more information about the failed pull. Check that the
image name is correct and try pulling the image manually on the host using docker pull. For
example, to manually pull an image from Docker Hub, use the command below:
If kubectl get pvc shows that your PVC status is Pending when using a Bitnami Helm chart, this may
be because your cluster does not support dynamic provisioning (such as a bare metal cluster). In this
case, the pod is unable to start because the cluster is unable to fulfil the request for a persistent
volume and attach it to the container.
To fix this, you must manually configure some persistent volumes or set up a StorageClass resource
and provisioner for dynamic volume provisioning, such as the NFS provisioner. Learn more about
VMware by Broadcom 91
VMware Tanzu Application Catalog Documentation - Tutorials
Are you unable to look up or resolve Kubernetes service names using DNS?
This usually occurs when the service has not been properly registered. The service may be using a
different namespace or may simply not be available. Try these steps:
Run these commands to check if the service is registered and the pods selected:
If the service is registered, run kubectl get pods, get the UID for your pod and then run the
command below. Replace the POD-UID placeholder with the pod UID and the SERVICE-
NAME placeholder with the DNS name of the service. This will give you an indication if the
DNS resolution is working or not.
If the error persists, then confirm that DNS is enabled for your Kubernetes cluster. If you're
using minikube, the command minikube addons list will give you a list of all enabled features.
If it is disabled, enable it and try again.
When running kubectl get nodes, you may see the following error:
This occurs because the authentication credentials are not correctly set. To resolve this, copy the
configuration file /etc/kubernetes/admin.conf to ~/.kube/config in a regular user account (with sudo
if necessary) and try again. This command should not be performed in the root user account.
cp /etc/kubernetes/admin.conf ~/.kube/config
This typically occurs when Kubernetes Role-Based Access Control (RBAC) is enabled, the default
situation from Kubernetes 1.6 onwards. To resolve this, you must create and deploy the necessary
RBAC policies for users and resources. Read our RBAC guide for more information and examples.
If using minikube, the command minikube ip will return the IP address of the node.
If not using minikube, the command kubectl get nodes -o yaml will show you, amongst other
VMware by Broadcom 92
VMware Tanzu Application Catalog Documentation - Tutorials
If your pod is running but appears to be non-responsive, it could be due to a failed process in the
container - for example, because of an invalid configuration or insufficient storage space. To check
this, you can log into the running container and check that the required processes are running.
To do this, first open a shell to the container and then, at the container shell, use ps to check for
running processes:
If the required process is not running, inspect the container logs to identify and resolve the issue.
VMware by Broadcom 93
VMware Tanzu Application Catalog Documentation - Tutorials
It is also helpful to look at the RESTARTS column of the kubectl get pods output to know if the pod is
repeatedly being restarted and the READY column to find out if the readiness probe (health check)
is executing positively.
Useful links
The following resources may be of interest to you:
VMware by Broadcom 94
VMware Tanzu Application Catalog Documentation - Tutorials
Introduction
This guide walks you through the basic Kubernetes network policy operations. First you are
introduced to the Kubernetes network policies and network plugins. Then you apply these concepts
to a multi-tier WordPress installation in kubeadm by completing the following steps:
At the end of this guide, you should be able to install a Kubernetes network plugin and apply
network policies in your cluster. The examples described in this guide were tested in kubeadm, but
they can be applied to any Kubernetes cluster.
By default, all pods in a Kubernetes cluster can communicate freely with each other without any
issues. In many environments, you can isolate the services running in pods from each other by
applying network restrictions. For example, the following can improve your cluster's security:
Only allow traffic between pods that form part of the same application. For example, in a
frontend-backend application, only allow communication to the backend from frontend pods.
Isolate pod traffic in namespaces. That is, a pod can only communicate with pods that belong
to the same namespace.
This guide shows you how you can use the Kubernetes network policies to apply these kinds of
restrictions. These restrictions can be combined with pod security policies which are explained in this
guide.
You have an advanced level of understanding of how Kubernetes works, and its core
resources and operations. You are expected to be familiar with concepts like:
Pods
VMware by Broadcom 95
VMware Tanzu Application Catalog Documentation - Tutorials
Deployments
Namespaces
Replicasets
PersistentVolumes
ConfigMaps
Nodes
The spec section of the policy outlines the key criteria a pod must fulfil in order to be allowed
to run.
Here is a brief description of the main options available (you can find more details in the
official Kubernetes API Reference):
podSelector: if the conditions defined in the next element apply, the podSelector
establishes which pods the network can accept traffic from (destination pods from
now on). Pods can be specified using the following criteria:
Network Policy Ingress Rules (ingress): establishes a set of allowed traffic rules. You
can specify:
from (origin pods): specifies which pods are allowed to access the previously
specified destination pods. Just like with destination pods, these origin pods
can be specified using NamespaceSelectors and LabelSelectors.
ports (allowed ports): specifies which destination pod's ports can be accessed
by the origin pods.
In a usable Kubernetes cluster, pods must be able to communicate between themselves, with
services and outside the cluster. Kubernetes is flexible enough (thanks to the use of the Container
Networking Interface), or CNI) to allow the administrator to choose between numerous container
network technologies (known as CNI plugins). Each one has its own properties and advantages (it is
out of the scope of this guide to go through all of them), but not all of them are compatible with the
Kubernetes network policies. The following are examples of compatible technologies:
VMware by Broadcom 96
VMware Tanzu Application Catalog Documentation - Tutorials
Calico
Weave
Romana
You can find more information on Kubernetes networking in Kubernetes official documentation.
Allow only traffic from Wordpress to MariaDB through port 3306 in a WordPress+MariaDB
installation.Crea
Deploy a WordPress Helm chart. We will use the name np-test so we know that the
WordPress pod will have the app: np-test-wordpress label and the MariaDB pod will have the
app: np-test-mariadb label.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
spec:
podSelector:
VMware by Broadcom 97
VMware Tanzu Application Catalog Documentation - Tutorials
After some time, check that the WordPress pod crashes because it cannot connect to the
MariaDB pod. This is expected as we restricted traffic between all pods.
Step 3: Allow traffic only from the WordPress pod to the MariaDB
pod
Now that we have restricted all network traffic between pods, we create an additional policy that
allows WordPress to connect to the MariaDB service. We can create additional network rules such as
this to ensure that we only allow traffic where needed.
Create a policy-wordpress-mariadb.yaml with the content below. In this yaml file you are
creating a network rule with the MariaDB pods (i.e. all pods with label app: np-test-mariadb)
as destination pods. In the network policy ingress rules, you set the WordPress pods (that is,
all pods with label app: np-test-wordpress) as the origin pods, and 3306 as the allowed port.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: db-frontend-allow
spec:
podSelector:
matchLabels:
app: np-test-mariadb
ingress:
- from:
- podSelector:
matchLabels:
app: np-test-wordpress
ports:
- protocol: TCP
port: 3306
Useful links
Now you are able to perform basic network policy operationIn this guide we walked you through the
concept of network policies and network plugins. Thanks to that, you were able to secure a multi-tier
application (Wordpress+MariaDB Helm chart) by isolating them from the rest of the cluster pods. This
is a first step in the numerous applications where network policies and network plugins offer to your
cluster. For more information, see the following links:
VMware by Broadcom 98
VMware Tanzu Application Catalog Documentation - Tutorials
Bitnami
VMware by Broadcom 99
VMware Tanzu Application Catalog Documentation - Tutorials
Introduction
As container technologies mature and more applications transition to clustered environments,
defining and implementing cluster security policies becomes ever more important. Cluster security
policies provide a framework to ensure that pods and containers run only with the appropriate
privileges and access only a finite set of resources. Security policies also provide a way for cluster
administrators to control resource creation, by limiting the capabilities available to specific roles,
groups or namespaces.
This guide introduces you to pod security policies in Kubernetes. It provides the definition, the
process of creation and activation, and the testing procedures. However, considering that pod
security policies are often tailored to an organization's rules and specific application requirements,
there is no universal solution. Instead, this guide will delve into three typical scenarios and guide you
through creating pod security policies tailored to each.
Note
You have a Kubernetes cluster running with the kubectl command-line tool installed and
support for pod security policies enabled.
You have an intermediate understanding of how Kubernetes works, and its core resources
and operations.
It's important to know that you can only use pod security policies if your Kubernetes cluster's
admission controller has them enabled. You can check this by running the command kubectl get
psp. If it's not supported, you'll see an error when you run this command.
The following image illustrates the difference in command output between a server that does not
support pod security policies and one that does:
If you are using Minikube, enable support for pod security policies and the other
recommended admission controller plugins by starting Minikube with the following command
(note the PodSecurityPolicy option at the end):
If you're using a different platform for your Kubernetes cluster, check the documentation
from the company that provides your cluster to see if they already support pod security
policies. If not, look for instructions on how to turn them on.
The examples in this guide have been tested using a Minikube cluster running Kubernetes v1.6.4,
but should be generally applicable to any Kubernetes cluster with pod security policy support.
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: example
spec:
privileged: false
runAsUser:
rule: MustRunAsNonRoot
seLinux:
rule: RunAsAny
fsGroup:
rule: RunAsAny
supplementalGroups:
rule: RunAsAny
volumes:
- 'nfs'
hostPorts:
- min: 100
max: 100
Briefly, this pod security policy implements the following security rules:
Disallow containers that access host ports apart from port 100
Later parts of this guide will delve into these rules with more detail. For now, let's examine the
overall structure of a pod security policy.
The spec section of the policy outlines the key criteria a pod must fulfil in order to be allowed
to run.
Here is a brief description of the main options available. To learn more, see official Kubernetes
documentation.
The privileged field indicates whether to allow containers that use privileged mode. Learn
more about privileged mode.
The runAsUser field defines which users a container can run as. Most commonly, it is
used to prevent pods from running as the root user.
The seLinux field defines the Security-Enhanced Linux (SELinux) security context for
containers and only allows containers that match that context. Learn more about
SELinux.
The supplementalGroups and fsGroup fields define the user groups or fsGroup-
owned volumes that a container may access. Learn more about fsGroups and
supplemental groups.
The volumes field defines the type(s) of volumes a container may access. Learn more
about volumes.
The hostPorts field, together with related fields like hostNetwork, hostPID and
hostIPC, restrict the ports (and other networking capabilities) that a container may
access on the host system.
To better explain how pod security policies work in practice, the following sections illustrate common
use cases and also walk you through the commands to add, view and remove pod security policies in
a cluster.
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: restrict-root
spec:
privileged: false
runAsUser:
rule: MustRunAsNonRoot
seLinux:
rule: RunAsAny
fsGroup:
rule: RunAsAny
supplementalGroups:
rule: RunAsAny
volumes:
- '*'
Activate the policy by executing the command below, which creates the new policy from the file:
Check that the policy has been installed with the command below, which lists all active policies in the
cluster:
Once the policy has been installed, the next step is to test it, by attempting to run a container that
requires root privileges. One such example is Bitnami's MariaDB container. Try to deploy it using the
command below:
Since the pod security policy explicitly disallows pods or containers with root privileges, this request
should be rejected and you should see an error like this when you check pod status:
Then, create a more permissive policy by setting the runAsUser field to runAsAny and save it as
permit-root.yaml. Here's what this more permissive policy looks like:
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: permit-root
spec:
privileged: false
runAsUser:
rule: RunAsAny
seLinux:
rule: RunAsAny
fsGroup:
rule: RunAsAny
supplementalGroups:
rule: RunAsAny
volumes:
- '*'
As before, install and activate the policy with the following command:
Now, delete the previous deployment and try deploying Bitnami's MariaDB container again. This
time, the deployment should take place successfully, as the new security policy allows containers to
run as any user, including the root user. Check the status with kubectl get pods and you should see
the pod running, as shown below:
Note
When a Kubernetes cluster is started with pod security policy support, Kubernetes
follows a "default-deny" approach. This means that, by default, pods are not allowed
to run unless they match the criteria outlined in a pod security policy. This also
means that if your cluster does not have at least one pod security policy in place, no
pods will run and Kubernetes will let you know that you should activate a pod security
policy with the error message no providers available to validate pod request.
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: restrict-volumes
spec:
privileged: false
runAsUser:
rule: RunAsAny
seLinux:
rule: RunAsAny
fsGroup:
rule: RunAsAny
supplementalGroups:
rule: RunAsAny
volumes:
- 'nfs'
Install this policy as explained in the previous section and then test it, by attempting to deploy a pod
that requests a different volume type. One such example is Bitnami's WordPress deployment, which
uses PersistentVolumeClaims (PVCs) and secrets for its data. Attempt to deploy it using the following
command:
Since the pod security policy only allows pods that use NFS volumes, this request should be rejected
and you should see an error like this when you check status:
Delete the policy and the failed deployment, and install a different policy that allows access to both
secret and PVC volume types, as shown below:
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: permit-volumes-pvc-secret
spec:
privileged: false
runAsUser:
rule: RunAsAny
seLinux:
rule: RunAsAny
fsGroup:
rule: RunAsAny
supplementalGroups:
rule: RunAsAny
volumes:
- 'persistentVolumeClaim'
- 'secret'
With this, your next attempt at deploying Bitnami WordPress should be successful:
or network interfaces. Pod security policies allow cluster administrators to implement in-depth
security rules to restrict such access. A simple example is restricting a container from accessing any
host ports, as shown below:
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: restrict-ports
spec:
privileged: false
runAsUser:
rule: RunAsAny
seLinux:
rule: RunAsAny
fsGroup:
rule: RunAsAny
supplementalGroups:
rule: RunAsAny
volumes:
- '*'
hostPorts:
- min: 0
max: 0
Install this policy as explained previously and then test it, by deploying a container that attempts to
map a container port to a host port. Bitnami's MariaDB container is well-suited for this experiment.
Try to deploy it and make it available on host port 3306 using the following command:
Since the pod security policy clearly states no to accessing the host port, your request will be denied.
When you check the deployment status, you'll likely see an error message like this:
Invalid value: 3306: Host port 3306 is not allowed to be used. Allowed ports: [{0 0}]
Delete the policy and the failed deployment, and install a different policy that allows restricted host
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: permit-port-3306
spec:
privileged: false
runAsUser:
rule: RunAsAny
seLinux:
rule: RunAsAny
fsGroup:
rule: RunAsAny
supplementalGroups:
rule: RunAsAny
volumes:
- '*'
hostPorts:
- min: 3306
max: 3306
You should now be able to deploy the Bitnami MariaDB container using the command shown
previously. Here is the result:
Useful links
These three examples show that pod security policies let cluster administrators control the pods and
containers in a Kubernetes cluster. They can allow or block access to resources based on
organizational rules and each application's needs. Pod security policies are easy to understand,
create, and implement, making them a valuable tool in a cluster administrator's security kit.
To learn more about the topics discussed in this guide, visit the following links:
Minikube
Bitnami
Introduction
When a container is built and/or used, it is important to ensure that the image is built by following
best practices in terms of security, efficiency, performance, etc. This article will go over some of the
key points VMware Tanzu Application Catalog (Tanzu Application Catalog) takes into account when
publishing containers. It covers image tagging, non-root configuration and arbitrary UIDs, the
importance of reducing size and dependencies, and the release process, including CVE scanning
and tests.
Every time Tanzu Application Catalog publishes a new version of an image, the associated tags are
also updated to make it easier for users to get the latest version.
Rolling tags
Tanzu Application Catalog uses rolling tags (a tag that may not always point to the same image) for its
Docker container images. To understand how this works, let's use the Tanzu Application Catalog
etcd container image tags as an example:
The latest tag always points to the latest revision of the etcd image.
The 3 tag is a rolling tag that always points to the latest revision of etcd 3.x.
The 3.4.13 tag is a rolling tag that points to the latest revision of etcd 3.4.13. It will be
updated with different revisions or daily releases but only for etcd 3.4.13.
The 3-debian-10 tag points to the latest revision of etcd 3.x for Debian 10, in case there are
other distros supported.
When Tanzu Application Catalog releases container images - typically to upgrade system packages -
it fixes bugs or improves the system configuration and also updates container tags to point to the
latest revision of the image. Therefore, the rolling tags shown above are dynamic; they will always
point to the latest revision or daily release of the corresponding image.
Continuing with the example above, the 3.4.13 tag might point to the etcd 3.4.13 revision 8 today,
but it will refer to the etcd 3.4.13 revision 9 when Tanzu Application Catalog next updates the
container image.
The suffix revision number (rXX) is incremented every time that Tanzu Application Catalog releases
an updated version of the image for the same version of the application. As explained in the next
section, suffixed tags are also known as immutable tags.
Immutable tags
A static, or immutable, tag always points to the same image. This is useful when you depend on a
specific revision of an image For example, if you use the tag 3.4.13-debian-10-r8, this tag will
always refer to etcd 3.4.13 revision 8. The use of this tag ensures that users get the same image
every time.
Usage recommendations
Which tag should you use and when? Follow these guidelines:
If you are using containers in a production environment (such as Kubernetes), use immutable
tags. Tanzu Application Catalog uses immutable tags by default in the Tanzu Application
Catalog Helm Charts. This ensures that your deployment won't be affected if a new revision
inadvertently breaks existing functionality.
If you are using containers for development, use rolling tags. This ensures that you are
always using the latest version. Rolling tags also make it easier to use a specific version of a
development tool (such as REGISTRY/node:12 for Node.js 12).
This section gives you a quick introduction to non-root container images, explains possible issues
you might face using them, and also shows how to modify them to work as root images.
Non-root containers
By default, Docker containers are run as root users. This means that you can do whatever you want
in the container, such as install system packages, edit configuration files, bind privilege ports, adjust
permissions, create system users and groups, or access networking information.
With a non-root container, you can't do any of this. A non-root container must be configured only
for its main purpose, for example, run the NGINX server.
A non-root container is a container in which the user executing the processes is not the root user
but a unprivileged user, like 1001. This is usually modified through the USER instruction in the
Dockerfile.
Security: Non-root containers are more secure. If there is a container engine security issue,
running the container as an unprivileged user will prevent any malicious code from gaining
elevated permissions on the container host. Learn more about Docker's security features.
Platform restrictions: Some Kubernetes distributions (such as OpenShift) run containers using
random UUIDs. This approach is not compatible with root containers, which must always run
with the root user's UUID. In such cases, root-only container images will simply not run and
a non-root image is a must. Learn more about random UUIDs
Write failures on mounted volumes: Docker mounts host volumes preserving the host UUID
and GUID. This can lead to permission conflicts with non-root containers, as the user running
the container may not have the appropriate privileges to write on the host volume.
Issues with specific utilities or services: Some utilities (eg. Git) or servers (eg. PostgreSQL)
run additional checks to find the user in the /etc/passwd file. These checks will fail for non-
root container images.
For Kubernetes, Tanzu Application Catalog Helm charts use an initContainer for changing
the volume permissions properly. As the image runs as non-root by default, it is necessary to
adjust the ownership of the persistent volume so that the container can write data to it. By
default, the charts are configured to use Kubernetes Security Context to automatically
change the ownership of the volume. However, this feature does not work in all Kubernetes
distributions. As an alternative, the charts support using an initContainer to change the
ownership of the volume before mounting it in the final destination.
For specific utilities, Tanzu Application Catalog ships the libnss-wrapper package, which
defines custom userspace files to ensure the software acts correctly.
In Kubernetes, the user that executes the container can be customized by using Security Context.
using that same user ID. This ensures the volume is only accessible to the appropriate container, but
requires that the image is able to run as an arbitrary user ID.
That means a non-root container executing on a platform with this policy can't assume anything
about the UUID. These platforms change the default container user to an arbitrary UUID, but the
GUID is unmodified and containers are executed as XXX:root (where XXX is the arbitrary UUID).
Tanzu Application Catalog images are configured with the proper permissions for the user and group
in order to meet the requirements of these platforms. They do this by ensuring that the XXX user
belongs to the root group and that the directories have the appropriate read, write and execution
permissions.
Although all Tanzu Application Catalog images follow this good practice, there are cases where two
or more processes need to be executed at the same time in the same image. One such case is that
of the Tanzu Application Catalog PostgreSQL with Replication Manager Docker Image where, apart
from the postgres process, there is a separate process for the repmgr daemon. There are also other
cases where the application spawns additional processes on its own.
It is therefore important to take a decision about the number of processes per container, keeping in
mind the goal of keeping each container as clean and modular as possible.
Do not allow containers to bypass the host system's authentication or ingress. For example,
Tanzu Application Catalog images do not run an SSH daemon inside the container.
In the same way, a good security practice is to install and maintain only the minimum necessary
dependencies in a container image. It is also important to reduce the size of the images to improve
the security, performance, efficiency, and maintainability of the containers.
packages in a smart way for container environments. Apart from installing packages only with the
required dependencies (no recommended packages or documentation), it also removes the cache
and unnecessary package repositories.
As explained previously, this approach means that a new immutable tag is produced every day,
increasing the revision number. At the same time, rolling tags are updated to point to this new
immutable tag.
Apart from daily releases, there are other processes that can trigger a new release. For example, if
there is a new version (major, minor, or patch) of the main component, Tanzu Application Catalog's
tracking system detects this new upstream release and trigger a new release of the Tanzu
Application Catalog image, which uses the -r0 tag suffix.
Before a new image is released, antivirus scanners and other tests are executed. If these are
unsuccessful, the release is blocked. These are discussed in the following sections
There are two ways of ensuring the health of containers: using a virus scan or a CVE scan.
The virus scan is executed during the release process. The virus scan performed by Tanzu
Application Catalog uses antivirus engines for scanning the files present in the container,
stopping the release if a positive is detected.
While the antivirus scan is a blocking step when releasing a container, the CVE scan is a tool
executed periodically to trigger new releases. This tool analyzes the containers bundled by
the Tanzu Application Catalog Helm charts. If it finds a CVE, it triggers the release of the
affected container.
Docker Compose, using several Docker Compose files to test different features like LDAP,
cluster topologies, etc.
Helm charts, tested on different Kubernetes platforms such as GKE, AKS, IKS, TKG, etc., and
under different scenarios.
Verification tests: This type of testing involves inspecting a deployment to check certain
properties. For example, checking if a particular file exists on the system and if it has the
correct permissions.
Functional tests: This type of testing is used to verify that an application is behaving as
expected from the user's perspective. For example, if the application must be accessible
using a web browser, functional testing uses a headless browser to interact with the
application and perform common actions such as logging in and out and adding users.
FIPS
Containers should follow modern cryptographic standards for security. If customers require
compliance with FIPS 140-2, Tanzu Application Catalog containers can ship a FIPS-enabled version
of OpenSSL. In a FIPS-enabled kernel, OpenSSL (and the applications using it) will only use FIPS-
approved encryption algorithms. In the case of applications that have a FIPS mode (such as
Elasticsearch), this would be enabled as well.
Conclusion
By implementing the above points in the Tanzu Application Catalog build and release process, Tanzu
Application Catalog ensures that its container images are built following best practices in terms of
security and performance and can be safely used on most platforms as part of production
deployments.
Introduction
When developing a chart, it is important to ensure that the packaged content (chart source code,
container images, and subcharts) is created by following best practices in terms of security, efficiency
and performance.
This article will go over the key points Bitnami takes into account when publishing Bitnami Helm
charts. It covers the best practices applied to the bundled containers, the use of configuration as
ConfigMaps, integration with logging and monitoring tools, and the release process, including CVE
scanning and tests.
In order to have full control over the published charts, an indispensable requirement for all Bitnami
Helm charts is that all the bundled images are released through the Bitnami pipeline following
Bitnami's best practices for securing and hardening containers.
Note
In our experience, deciding which data should or should not be persistent can be
complicated. After several iterations, our recommended approach has been to use
ConfigMaps, but this recommendation could change depending on the configuration
file or scenario. One advantage of Kubernetes is that users can change the
deployment parameters very easily by just executing kubectl edit deployment or
helm upgrade. If the configuration is persistent, none of the changes will be applied.
So, when developing Bitnami Helm charts, we make sure that the configuration can
be easily changed with kubectl or helm upgrade.
One common practice is to create a ConfigMap with the configuration and have it mounted in the
container. Let's use the Bitnami RabbitMQ chart as an example:
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ template "rabbitmq.fullname" . }}-config
namespace: {{ .Release.Namespace }}
labels: {{- include "common.labels.standard" . | nindent 4 }}
data:
rabbitmq.conf: |-
{{- include "common.tplvalues.render" (dict "value" .Values.configuration "context
" $) | nindent 4 }}
{{- if .Values.advancedConfiguration}}
advanced.config: |-
{{- include "common.tplvalues.render" (dict "value" .Values.advancedConfiguration
"context" $) | nindent 4 }}
{{- end }}
Note that there is a section in the values.yaml file which allows you to include custom configuration:
This ConfigMap then gets mounted in the container filesystem, as shown in this extract of the
StatefulSet spec:
volumes:
- name: configuration
configMap:
name: {{ template "rabbitmq.fullname" . }}-config
items:
- key: rabbitmq.conf
path: rabbitmq.conf
{{- if .Values.advancedConfiguration}}
- key: advanced.config
path: advanced.config
{{- end }}
This approach makes Bitnami charts easy to upgrade and also more adaptable to user needs, as
users can provide their own custom configuration file.
Bitnami charts are developed ensuring that deployments are able to work with the above tools
seamlessly. To achieve this, the Bitnami charts ensure that:
All the containers log to stdout/stderr (so that the EFK stack can easily ingest all the logging
information)
Prometheus exporters are included (either using sidecar containers or having a separate
deployment)
Bitnami offers the Bitnami Kubernetes Production Runtime (BKPR) that installs all these tools (along
with others) and makes your cluster capable of handling production workloads. All Bitnami charts
work with BKPR (which includes EFK and Prometheus) out of the box. Let's take a look at the
Bitnami PostgreSQL chart and Bitnami PostgreSQL container to see how this is achieved.
To begin with, the process inside the container runs in the foreground, so all the logging information
is written to stdout/stderr, as shown below:
Although there are different approaches to implement logging capabilities, such as adding a logging
agent at the node level or configuring the application to push the info to the backend, the most
common approach is to use sidecar containers. For more information, see logging architectures.
In the example above, the chart adds a sidecar container for Prometheus metrics:
containers:
{{- if .Values.metrics.enabled }}
- name: metrics
image: {{ template "postgresql.metrics.image" . }}
imagePullPolicy: {{ .Values.metrics.image.pullPolicy | quote }}
{{- if .Values.metrics.securityContext.enabled }}
securityContext:
runAsUser: {{ .Values.metrics.securityContext.runAsUser }}
{{- end }}
env:
{{- $database := required "In order to enable metrics you need to specify
a database (.Values.postgresqlDatabase or .Values.global.postgresql.postgresqlDatabase
)" (include "postgresql.database" .) }}
{{- $sslmode := ternary "require" "disable" .Values.tls.enabled }}
{{- end }}
{{- if .Values.metrics.customMetrics }}
- name: custom-metrics
mountPath: /conf
readOnly: true
args: ["--extend.query-path", "/conf/custom-metrics.yaml"]
{{- end }}
ports:
- name: http-metrics
containerPort: 9187
{{- if .Values.metrics.resources }}
resources: {{- toYaml .Values.metrics.resources | nindent 12 }}
{{- end }}
{{- end }}
Bitnami also ensures that the pods or services contain the proper annotations for Prometheus to
detect exporters. In this case, they are defined in the chart's values.yaml file, as shown below:
In the case of the PostgreSQL chart, these annotations go to a metrics service, separate from the
PostgreSQL service, which is defined as below:
{{- if .Values.metrics.enabled }}
apiVersion: v1
kind: Service
metadata:
name: {{ template "postgresql.fullname" . }}-metrics
labels:
{{- include "common.labels.standard" . | nindent 4 }}
annotations:
{{- if .Values.commonAnnotations }}
{{- include "postgresql.tplValue" ( dict "value" .Values.commonAnnotations "contex
t" $ ) | nindent 4 }}
{{- end }}
{{- toYaml .Values.metrics.service.annotations | nindent 4 }}
spec:
type: {{ .Values.metrics.service.type }}
{{- if and (eq .Values.metrics.service.type "LoadBalancer") .Values.metrics.service.
loadBalancerIP }}
loadBalancerIP: {{ .Values.metrics.service.loadBalancerIP }}
{{- end }}
ports:
- name: http-metrics
port: 9187
targetPort: http-metrics
selector:
{{- include "common.labels.matchLabels" . | nindent 4 }}
role: master
{{- end }}
Some parameters related to the metrics exporter can be configured in the values.yaml:
Apart from all of the above, this container has its own probes, environment variables and security
context.
These modifications ensure that Bitnami charts seamlessly integrate with monitoring platforms. The
metrics obtained can be used to keep the deployment in good condition throughout its lifetime.
Upstream new version: If there is a new version of the main container bundled in the chart,
Bitnami triggers a new release.
Maintenance release: If there was no update in the last 30 days (this time period can be
customized for charts released as part of the VMware Tanzu Application Catalog(TM), Bitnami
triggers a new release.
CVE detected: Bitnami triggers a release of a chart when a package that includes a fix for a
CVE is detected.
User PR: When a pull request or any other change performed by a user or the Bitnami team
is merged into the Bitnami GitHub repository, Bitnami triggers a new release.
In all the above cases, the main image is updated to the latest version and the secondary containers
(such as metrics exporters) and chart dependencies are also updated to the latest published version
at that time.
However, before the release is performed, various scanners and tests are executed. These stop the
release from proceeding if the result is not successful.
CVE scanning
To ensure that all Bitnami images include the latest security fixes, Bitnami implements the following
policies:
Bitnami triggers a release of a new Helm chart when a new version of the main server or
application is detected. For example, if the system automatically detects a new version of
RabbitMQ, Bitnami’s pipeline automatically releases a new container with that version and
also releases the corresponding Helm chart if it passes all tests. This way, Bitnami ensures
that the application version released is always the latest stable one and has the latest security
fixes.
The system scans all Bitnami containers and releases new images daily with the latest
available system packages. Once the pipeline detects there is a new package that fixes a
CVE, our team triggers the release of a new Helm chart to point to the latest container
images.
The Bitnami team monitors different CVE feeds - such as Heartbleed or Shellshock - to fix
the most critical issues as soon as possible. Once a critical issue is detected in any of the
charts included in the Bitnami catalog (or any of the assets that Bitnami distributes amongst its
different cloud providers), a new solution is released. Usually, Bitnami provides updates in
less than 48 business hours.
Note
Open CVEs are CVEs that depend directly on the Linux distribution maintainers and
have not yet been fixed by those maintainers. Bitnami is not able to fix such CVEs
directly. Learn more about Bitnami's open CVE policy.
Verification tests: This type of testing involves inspecting a deployment to check certain
properties. For example, checking if a particular file exists on the system and if it has the
correct permissions.
Functional tests: This type of testing is used to verify that an application is behaving as
expected from the user's perspective. For example, if the application must be accessible
using a web browser, functional testing uses a headless browser to interact with the
application and perform common actions such as logging in and out and adding users.
Upgrade tests
One of the most common use cases for Helm charts is the upgrade process. Helm charts follow the
SemVer specification (MAJOR.MINOR.PATCH) to handle chart version numbering. According to that
specification, backward compatibility should be guaranteed for MINOR and PATCH versions, while it
is not guaranteed in MAJOR versions.
From Bitnami, when a new change is implemented in the chart, the Bitnami team determine the
version number change required. Typically, bug fixes are PATCH changes, feature additions are
MINOR changes and MAJOR changes occur when backward compatibility cannot be guaranteed.
In the case of MAJOR versions, the changes and, if possible, an upgrade path is documented in the
README. Here is an example from the PostgreSQL chart.
When the changes are not MAJOR changes, backward compatibility should be guaranteed. To test
this, Bitnami applies a "Chart Upgrade" test as part of the Bitnami release pipeline to ensure that
helm upgrade works for non-major changes. In this test:
The first available version in the current major version is installed (such as X.0.0).
The helm upgrade command is executed to install the most recent version (such as X.3.5).
Tests are executed to check that the populated data is still present in the upgraded chart.
Bitnami has also published some guides about how to backup and restore deployments in
Kubernetes for common infrastructure charts like MongoDB and MariaDB Galera.
Conclusions
By implementing the above steps in the Bitnami package and release process, Bitnami ensures that
its Helm charts are packaged following best practices in terms of security and performance and can
be safely used on most platforms as part of production deployments.
Useful links
To learn more about the topics discussed in this guide, use the links below:
Introduction
Note
Did you know Bitnami automatically releases new tags under the following
circumstances?
If there are changes in the configuration scripts: new features, improvements, bug fixes, etc
impacting Dockerfile, bash logic, ...
Container image tags uniquely identify a container image, allowing you to deploy a specific version of
an image. A single image can have multiple tags associated with it. Typically, every time you publish
a new version of an image, you will also update its tags to make it easier for your users to get the
latest version.
This guide will explain Bitnami's tagging system and how you can use it to identify different versions
of its container images.
Rolling tags
Bitnami uses rolling tags for its container images. To understand how this works, let's look at the tags
for the Bitnami WordPress container image:
The latest tag always points to the latest revision of the WordPress image.
The 6 tag is a rolling tag that always points to the latest revision of WordPress 6.y.z
The 6-debian-12 tag points to the latest revision of WordPress 6.y.z for Debian 12.
The 6.4.3 tag is a rolling tag that points to the latest revision of WordPress 6.4.3. It will be
updated with different revisions or daily releases but only for WordPress 6.4.3.
When Bitnami revises container images, typically to upgrade system packages, fix bugs or improve
system configuration, it also updates the container tags to point to the latest revision of the image.
Therefore, the rolling tags shown above are dynamic; they will always point to the latest revision or
daily release for the corresponding image.
As an example, the 6.4.3 tag might point to WordPress 6.4.3 revision 10 now but will refer to
WordPress 6.4.3 revision 11 when Bitnami next updates the container image. The suffix revision
number (rXX) is incremented every time Bitnami releases an updated version of the image for the
same version of the application.
It is worth noting that any tags that do not explicitly specify a distribution should be assumed to refer
to the base image used in the Bitnami Application Catalog, at this moment, Debian 12.
Immutable tags
What if you depend on a specific revision of an image? For these scenarios, Bitnami also attaches a
static (immutable) tag to each revision. In this example, the 6.4.3-debian-12-r10 tag refers to
WordPress 6.4.3 revision 10, and using this tag ensures that users always get the same image every
time.
Usage recommendations
Which tag should you use and when? Follow these guidelines:
If you are using containers for development, Bitnami suggests using rolling tags. This ensures
that you are always using the latest version. Rolling tags also make it easier to use a specific
version of a development tool (such as bitnami/node:18 for Node.js 18).
Useful links
To learn more, consider visiting the following links:
Introduction
Developers are increasingly adopting containers as their preferred way to build cloud-native
applications. They are portable, easy to use and consistent. Bitnami provides a wide range of pre-
packaged Docker containers. These ready-to-use assets follow the industry best practices, and
bundle the most up to date and secure versions of applications and their components.
Creating regular backups of your container deployments is a good practice that prevents data loss,
and gives the ability to restore your backup elsewhere.
This guide shows you how to create a backup of your container's persisted data and restore it using
Bitnami container images. It uses the Bitnami WordPress image as an example, but you can follow
this guide using any other Bitnami container image.
You are running a Bitnami container image that mounts persistent volumes and includes
custom data that you wish to back up.
You are running a solution which is comprised of two containers: one for the application and
another for the database.
IMPORTANT Some Bitnami images use a single container and others use more than one container.
The example WordPress container image used in this guide uses two separate containers, one for
the application and another for the database. To backup and restore the application data, you must
backup and restore all volumes mounted in each container.
Note
To back up your container data, you must generate a tar.gz file within the backup directory in each
container. In this case, backup both the volumes mounted in the application container and the
database container. Follow these instructions:
TIP Some Bitnami containers such as Magento, create extra volumes apart for the application and
database ones. Check out container's docker-compose.yml file to learn which are the volumes that
your container will mount.
$ docker-compose ps -q wordpress
$ docker-compose ps -q mariadb
$ docker-compose stop
Stopping wp_wordpress_1 ... done
Stopping wp_mariadb_1 ... done
Execute the commands below to create a backup file for each container. Remember to
replace the CONTAINER-WORDPRESS and CONTAINER-MARIADB placeholder with the
corresponding WordPress or MariaDB container ID.
Check that you own the right permissions on the backup file:
$ ls -lah backup/wordpress_data_backup.tar.gz
Your data is now restored. You can check it by accessing the application and verifying that the data
exists and the application is functioning correctly.
Useful links
To learn more about the topics discussed in this guide, use the links below:
Bitnami Containers
Introduction
VMware Tanzu Application Catalog (Tanzu Application Catalog) offers Helm charts for popular
applications and infrastructure components like WordPress, MySQL, Elasticsearch and many others.
These charts let you deploy your applications and infrastructure on Kubernetes in a secure and
reliable manner without worrying about packaging, dependencies or Kubernetes YAML file
configurations.
Once you have your applications and your infrastructure running on Kubernetes, you need to start
thinking about how to backup the data flowing in and out of your cluster, so that you can protect
yourself from a failure or service outage. That's where Velero comes in.
Velero is an open source tool that makes it easy to backup and restore Kubernetes resources. It can
be used to back up an entire cluster, or it can be fine-tuned to only backup specific deployments
and/or namespaces. This guide gets you started with Velero by showing you how to use it to backup
and restore deployments created with Tanzu Application Catalog's Helm charts.
You have two separate multi-node Kubernetes cluster - a source cluster and a destination
cluster - running on the same cloud provider. This guide uses the Google Kubernetes
Engine (GKE) service from Google Cloud Platform but you can use any cloud provider
supported by Velero. Learn about the providers supported by Velero.
You have configured Helm to use the Tanzu Application Catalog chart repository following
the instructions for Tanzu Application Catalog or the instructions for VMware Tanzu
Application Catalog for Tanzu Advanced.
You have the kubectl CLI and the Helm v3.x package manager installed and configured to
work with your Kubernetes clusters. Learn how to install kubectl and Helm v3.x.
This guide uses the Tanzu Application Catalog WordPress Helm chart as an example and describes
how to backup and restore all the components of a Tanzu Application Catalog WordPress
deployment created with this chart from one cluster to another. The steps are similar for other Tanzu
Application Catalog Helm charts.
cluster
NOTE
This step creates a fresh WordPress deployment using Tanzu Application Catalog's
Helm chart and then customizes it to simulate a real-world backup/restore scenario.
If you already have a customized Tanzu Application Catalog WordPress deployment,
you can go straight to Step 2.
1. Modify your context to reflect the source cluster. Deploy WordPress on the source cluster
and make it available at a public load balancer IP address. Replace the PASSWORD
placeholder with a password for your WordPress dashboard and the REPOSITORY
placeholder with a reference to your Tanzu Application Catalog chart repository.
2. Wait for the deployment to complete and then use the command below to obtain the load
balancer IP address:
kubectl get svc --namespace default wordpress --template "{{ range (index .stat
us.loadBalancer.ingress 0) }}{{.}}{{ end }}"
3. Browse to the IP address and log in to the WordPress dashboard using the password
specified at deployment-time. Create and publish a sample post with a title, body, category
and image.
4. Confirm that you see the new post in the WordPress blog, as shown below:
1. Modify your context to reflect the source cluster (if not already done).
2. Follow the plugin setup instructions for your cloud provider. For example, if you are using
Google Cloud Platform (as this guide does), follow the GCP plugin setup instructions to create
a service account and storage bucket and obtain a credentials file.
3. Then, install Velero by executing the command below, remembering to replace the
BUCKET-NAME placeholder with the name of your storage bucket and the SECRET-
FILENAME placeholder with the path to your credentials file:
You should see output similar to the screenshot below as Velero is installed:
4. Confirm that the Velero deployment is successful by checking for a running pod using the
command below:
TIP: The previous command uses a label to select and backup only the resources related to the
WordPress deployment. Optionally, you can backup all deployments in a specific namespace with
the --include-namespaces parameter, or backup the entire cluster by omitting all selectors.
Execute the command below to view the contents of the backup and confirm that it contains all the
required resources:
At this point, your backup is ready. You can repeat this step every time you wish to have a manual
backup, or you can configure a schedule for automatic backups.
2. Install Velero on the destination cluster as described in Step 2. Remember to use the same
values for the BUCKET-NAME and SECRET-FILENAME placeholders as you did originally, so
that Velero is able to access the previously-saved backups.
3. Confirm that the Velero deployment is successful by checking for a running pod using the
command below:
4. To avoid the backup data being overwritten, switch the bucket to read-only access:
6. Restore the backup. Note that this may take a few minutes to complete.
Wait until the backed-up resources are fully deployed and active. Use the kubectl get pods and
kubectl get svc commands to track the status of the pods and service endpoint. Once the
deployment has been restored, browse to the load balancer IP address and confirm that you see the
same post content as that on the source cluster.
At this point, you have successfully restored the Tanzu Application Catalog Helm deployment chart
using Velero.
TIP: A new public IP address will be associated with the load balancer service after the deployment is
restored. If you configured a domain to point to the original public IP address, remember to
reconfigure your DNS settings to use the new public IP address after restoring the deployment.
Useful links
To learn more about the topics discussed in this guide, use the links below:
Velero documentation
Introduction
VMware Tanzu Application Catalog's (Tanzu Application Catalog) Apache Cassandra Helm chart
makes it easy to deploy a scalable Apache Cassandra database cluster on Kubernetes. This Helm
chart is compliant with current best practices and can also be easily upgraded to ensure that you
always have the latest fixes and security updates.
Once the database cluster is deployed and in use, it's necessary to put a data backup/restore
strategy in place. This backup/restore strategy is needed for many operational scenarios, including
disaster recovery planning, off-site data analysis or application load testing.
This guide explains how to back up and restore an Apache Cassandra deployment on Kubernetes
using Velero, an open-source Kubernetes backup/restore tool.
You have two separate Kubernetes clusters - a source cluster and a destination cluster - with
kubectl and Helm v3 installed. This guide uses Google Kubernetes Engine (GKE) clusters
but you can also use any other Kubernetes provider. Learn how to install kubectl and Helm
v3.x.
You have configured Helm to use the Tanzu Application Catalog chart repository following
the instructions for Tanzu Application Catalog or the instructions for VMware Tanzu
Application Catalog for Tanzu Advanced.
You have previously deployed the Tanzu Application Catalog Apache Cassandra Helm chart
on the source cluster and added some data to it. Example command sequences to perform
these tasks are shown below, where the PASSWORD placeholder refers to the database
administrator password and the cluster is deployed with 3 replicas. Replace the
REPOSITORY and REGISTRY placeholders with references to your Tanzu Application
Catalog chart repository and container registry.
-10-r20 -- bash
cqlsh -u admin -p $CASSANDRA_PASSWORD cassandra
CREATE KEYSPACE IF NOT EXISTS test WITH REPLICATION= {'class': 'SimpleStrategy'
, 'replication_factor': '2' } ;
USE test;
CREATE TABLE items (id UUID PRIMARY KEY, name TEXT);
INSERT INTO items (id, name) VALUES (now(), 'milk');
INSERT INTO items (id, name) VALUES (now(), 'eggs');
exit
Both clusters are on the same Kubernetes provider, as this is a requirement of Velero's
native support for migrating persistent volumes.
The restored deployment on the destination cluster will have the same name, namespace
and credentials as the original deployment on the source cluster.
NOTE
For persistent volume migration across cloud providers with Velero, you have the
option of using Velero's Restic integration. This integration is not covered in this
guide.
1. Modify your context to reflect the source cluster (if not already done).
2. Follow the Velero plugin setup instructions for your cloud provider. For example, if you are
using Google Cloud Platform (as this guide does), follow the GCP plugin setup instructions to
create a service account and storage bucket and obtain a credentials file.
3. Then, install Velero on the source cluster by executing the command below, remembering
to replace the BUCKET-NAME placeholder with the name of your storage bucket and the
SECRET-FILENAME placeholder with the path to your credentials file:
You should see output similar to the screenshot below as Velero is installed:
4. Confirm that the Velero deployment is successful by checking for a running pod using the
command below:
1. Create a backup of the volumes in the running Apache Cassandra deployment on the source
cluster. This backup will contain both the primary and secondary node volumes.
2. Execute the command below to view the contents of the backup and confirm that it contains
all the required resources:
3. To avoid the backup data being overwritten, switch the bucket to read-only access:
2. Install Velero on the destination cluster as described in Step 1. Remember to use the same
values for the BUCKET-NAME and SECRET-FILENAME placeholders as you did originally, so
that Velero is able to access the previously-saved backups.
3. Confirm that the Velero deployment is successful by checking for a running pod using the
command below:
4. Restore the persistent volumes in the same namespace as the source cluster using Velero.
6. Create a new Apache Cassandra deployment. Use the same name, namespace and cluster
topology as the original deployment. Replace the PASSWORD placeholder with the same
database administrator password used in the original deployment and the REPOSITORY
placeholder with a reference to your Tanzu Application Catalog chart repository.
NOTE: If using Tanzu Application Catalog for Tanzu Advanced, install the chart following the
steps described in the VMware Tanzu Application Catalog for Tanzu Advanced
documentation instead.
NOTE: The deployment command shown above is only an example. It is important to create
the new deployment on the destination cluster using the same namespace, deployment
name, credentials and cluster topology as the original deployment on the source cluster.
This will create a new deployment that uses the original pod volumes (and hence the original
data).
7. Connect to the new deployment and confirm that your original data is intact using a query
like the example shown below. Replace the PASSWORD placeholder with the database
administrator password and the REGISTRY placeholder with a reference to your Tanzu
Application Catalog container registry.
Useful links
Apache Cassandra Helm chart
Velero documentation
Introduction
Apache Kafka is a scalable and highly-available data streaming platform. It is a powerful tool for
stream processing and is available under an open source license.
VMware Tanzu Application Catalog's (Tanzu Application Catalog) Apache Kafka Helm chart makes it
easy to get started with an Apache Kafka cluster on Kubernetes. This Helm chart is compliant with
current best practices and can also be easily upgraded to ensure that you always have the latest fixes
and security updates.
Once the cluster is deployed and in operation, it is important to back up its data regularly and ensure
that it can be easily restored as needed. Data backup and restore procedures are also important for
other scenarios, such as off-site data migration/data analysis or application load testing.
This guide explains how to back up and restore an Apache Kafka deployment on Kubernetes using
Velero, an open-source Kubernetes backup/restore tool.
You have two separate Kubernetes clusters - a source cluster and a destination cluster - with
kubectl and Helm v3 installed. This guide uses Google Kubernetes Engine (GKE) clusters
but you can also use any other Kubernetes provider. Learn how to install kubectl and Helm
v3.x.
You have configured Helm to use the Tanzu Application Catalog chart repository following
the instructions for Tanzu Application Catalog or the instructions for VMware Tanzu
Application Catalog for Tanzu Advanced.
You have previously deployed the Tanzu Application Catalog Apache Kafka Helm chart on
the source cluster and added some data to it. Example command sequences to perform
these tasks are shown below. Replace the REPOSITORY and REGISTRY placeholders with
references to your Tanzu Application Catalog chart repository and container registry.
>third
exit
Both clusters are on the same Kubernetes provider, as this is a requirement of Velero's
native support for migrating persistent volumes.
The restored deployment on the destination cluster will have the same name, namespace
and credentials as the original deployment on the source cluster.
NOTE
For persistent volume migration across cloud providers with Velero, you have the
option of using Velero's Restic integration. This integration is not covered in this
guide.
1. Modify your context to reflect the source cluster (if not already done).
2. Follow the Velero plugin setup instructions for your cloud provider. For example, if you are
using Google Cloud Platform (as this guide does), follow the GCP plugin setup instructions to
create a service account and storage bucket and obtain a credentials file.
3. Then, install Velero on the source cluster by executing the command below, remembering
to replace the BUCKET-NAME placeholder with the name of your storage bucket and the
SECRET-FILENAME placeholder with the path to your credentials file:
You should see output similar to the screenshot below as Velero is installed:
4. Confirm that the Velero deployment is successful by checking for a running pod using the
command below:
1. Create a backup of the volumes in the running Apache Kafka deployment on the source
cluster. This backup will contain both the primary and secondary node volumes.
2. Execute the command below to view the contents of the backup and confirm that it contains
all the required resources:
3. To avoid the backup data being overwritten, switch the bucket to read-only access:
2. Install Velero on the destination cluster as described in Step 1. Remember to use the same
values for the BUCKET-NAME and SECRET-FILENAME placeholders as you did originally, so
that Velero is able to access the previously-saved backups.
3. Confirm that the Velero deployment is successful by checking for a running pod using the
command below:
4. Restore the persistent volumes in the same namespace as the source cluster using Velero.
6. Create a new Apache Kafka deployment. Use the same name, namespace and cluster
topology as the original deployment. Replace the PASSWORD placeholder with the same
administrator password used in the original deployment and the REPOSITORY placeholder
with a reference to your Tanzu Application Catalog chart repository.
NOTE: If using Tanzu Application Catalog for Tanzu Advanced, install the chart following the
steps described in the Tanzu Application Catalog for Tanzu Advanced documentation
instead.
NOTE: The deployment command shown above is only an example. It is important to create
the new deployment on the destination cluster using the same namespace, deployment
name, credentials and cluster topology as the original deployment on the source cluster.
This will create a new deployment that uses the original pod volumes (and hence the original
data).
7. Connect to the new deployment and confirm that your original messages are intact using a
query like the example shown below. Replace the REGISTRY placeholder with a reference to
your Tanzu Application Catalog container registry.
Useful links
Apache Kafka Helm chart
Velero documentation
Introduction
etcd is a reliable and efficient key-value store, most commonly used for data storage in distributed
systems. It offers a simple interface for reading and writing data and is available under an open
source license.
VMware Tanzu Application Catalog (Tanzu Application Catalog) offers an etcd Helm chart that
enables quick and easy deployment of an etcd cluster on Kubernetes. This Helm chart is compliant
with current best practices and is suitable for use in production environments, with built-in features
for role-based access control (RBAC), horizontal scaling, disaster recovery and TLS.
Of course, the true business value of an etcd cluster comes not from the cluster itself, but from the
data that resides within it. It is critical to protect this data, by backing it up regularly and ensuring that
it can be easily restored as needed. Data backup and restore procedures are also important for other
scenarios, such as off-site data migration/data analysis or application load testing.
This guide walks you through two different approaches you can follow when backing up and
restoring Tanzu Application Catalog etcd Helm chart deployments on Kubernetes:
Back up the data from the source deployment and restore it in a new deployment using
etcd's built-in backup/restore tools.
Back up the persistent volumes from the source deployment and attach them to a new
deployment using Velero, a Kubernetes backup/restore tool.
You have two separate Kubernetes clusters - a source cluster and a destination cluster - with
kubectl and Helm v3 installed. This guide uses Google Kubernetes Engine (GKE) clusters
but you can also use any other Kubernetes provider. Learn how to install kubectl and Helm
v3.x.
You have configured Helm to use the Tanzu Application Catalog chart repository following
the instructions for Tanzu Application Catalog or the instructions for VMware Tanzu
Application Catalog for Tanzu Advanced.
You have previously deployed the Tanzu Application Catalog etcd Helm chart on the source
cluster and added some data to it. Example command sequences to perform these tasks are
shown below, where the PASSWORD placeholder refers to the etcd administrator password.
Replace the REPOSITORY placeholder with a reference to your Tanzu Application Catalog
chart repository.
1. Forward the etcd service port and place the process in the background:
2. Create a directory for the backup files and make it the current working directory:
mkdir etcd-backup
chmod o+w etcd-backup
cd etcd-backup
3. Use the etcdctl tool to create a snapshot of the etcd cluster and save it to the current
directory. If this tool is not installed on your system, use Tanzu Application Catalog's etcd
Docker image to perform the backup, as shown below (replace the example container
registry shown with your Tanzu Application Catalog container registry). Replace the
PASSWORD placeholder with the administrator password set at deployment-time and the
REGISTRY placeholder with a reference to your Tanzu Application Catalog container registry.
Here, the --net parameter lets the Docker container use the host's network stack and
thereby gain access to the forwarded port. The etcdctl command connects to the etcd
service and creates a snapshot in the /backup directory, which is mapped to the current
directory (etcd-backup/) on the Docker host with the -v parameter. Finally, the --rm
parameter deletes the container after the etcdctl command completes execution.
4. Stop the service port forwarding by terminating the corresponding background process.
At the end of this step, the backup directory should contain a file named mybackup, which is a
snapshot of the data from the etcd deployment.
1. Begin by installing the NFS Server Provisioner. The easiest way to get this running on any
platform is with the stable Helm chart. Use the command below, remembering to adjust the
storage size to reflect your cluster's settings:
2. Create a Kubernetes manifest file named etcd.yaml to configure an NFS-backed PVC and a
pod that uses it, as below. Replace the REGISTRY placeholder with a reference to your
Tanzu Application Catalog container registry.
## etcd.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: etcd-backup-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 2Gi
storageClassName: nfs
---
apiVersion: v1
kind: Pod
metadata:
name: etcd-backup-pod
spec:
volumes:
- name: etcd-backup
persistentVolumeClaim:
claimName: etcd-backup-pvc
containers:
- name: inspector
image: REGISTRY/tac-shell:latest
command:
- sleep
- infinity
volumeMounts:
- mountPath: "/backup"
name: etcd-backup
This will create a pod named etcd-backup-pod with an attached PVC named etcd-backup-
pvc. The PVC will be mounted at the /backup mount point of the pod.
5. Verify that the snapshot exists in the PVC, by connecting to the pod command-line shell and
inspecting the /backup directory:
The command output should display a directory listing containing the snapshot file, as shown
below:
1. Create a new etcd deployment. Replace the PASSWORD placeholder with the same
password used in the original deployment and replace the REPOSITORY placeholder with a
reference to your Tanzu Application Catalog chart repository.
This command creates a new etcd cluster and initializes it using an existing data snapshot.
The startFromSnapshot.existingClaim and startFromSnapshot.snapshotFilename define
the source PVC and source filename for the snapshot respectively.
NOTE: It is important to create the new deployment on the destination cluster using the
same credentials as the original deployment on the source cluster.
2. Connect to the new deployment and confirm that your data has been successfully restored.
Replace the PASSWORD placeholder with the administrator password set at deployment-
time.
NOTE
Tanzu Application Catalog's etcd Helm chart also supports auto disaster recovery by
periodically snapshotting the keyspace. If the cluster permanently loses more than
(N-1)/2 members, it tries to recover the cluster from a previous snapshot. Learn more
about this feature.
Both clusters are on the same Kubernetes provider, as this is a requirement of Velero's
native support for migrating persistent volumes.
The restored deployment on the destination cluster will have the same name, namespace,
topology and credentials as the original deployment on the source cluster.
NOTE
For persistent volume migration across cloud providers with Velero, you have the
option of using Velero's Restic integration. This integration is not covered in this
guide.
1. Modify your context to reflect the source cluster (if not already done).
2. Follow the Velero plugin setup instructions for your cloud provider. For example, if you are
using Google Cloud Platform (as this guide does), follow the GCP plugin setup instructions to
create a service account and storage bucket and obtain a credentials file.
3. Then, install Velero on the source cluster by executing the command below, remembering
to replace the BUCKET-NAME placeholder with the name of your storage bucket and the
SECRET-FILENAME placeholder with the path to your credentials file:
You should see output similar to the screenshot below as Velero is installed:
4. Confirm that the Velero deployment is successful by checking for a running pod using the
command below:
1. Create a backup of the volumes in the running etcd deployment on the source cluster. This
backup will contain all the node volumes.
2. Execute the command below to view the contents of the backup and confirm that it contains
all the required resources:
3. To avoid the backup data being overwritten, switch the bucket to read-only access:
2. Install Velero on the destination cluster as described in Step 1. Remember to use the same
values for the BUCKET-NAME and SECRET-FILENAME placeholders as you did originally, so
that Velero is able to access the previously-saved backups.
3. Confirm that the Velero deployment is successful by checking for a running pod using the
command below:
4. Restore the persistent volumes in the same namespace as the source cluster using Velero.
6. Create a new etcd deployment. Use the same deployment name, credentials and other
parameters as the original deployment. Replace the PASSWORD placeholder with the same
database password used in the original release and the REPOSITORY placeholder with a
reference to your Tanzu Application Catalog chart repository.
NOTE: It is important to create the new deployment on the destination cluster using the
same namespace, deployment name, credentials and number of replicas as the original
deployment on the source cluster.
This will create a new deployment that uses the original volumes (and hence the original
data).
7. Connect to the new deployment and confirm that your original data is intact:
Useful links
Tanzu Application Catalog etcd Helm chart
Velero documentation
Introduction
VMware Tanzu Application Catalog (Tanzu Application Catalog) offers a MongoDB Helm chart that
makes it quick and easy to deploy a horizontally-scalable MongoDB cluster on Kubernetes with
separate primary, secondary and arbiter nodes. This Helm chart is compliant with current best
practices and can also be easily upgraded to ensure that you always have the latest fixes and security
updates.
However, setting up a scalable MongoDB service is just the beginning; you also need to regularly
backup the data being stored in the service, and to have the ability to restore it elsewhere if needed.
Common scenarios for such backup/restore operations include disaster recovery, off-site data
analysis or application load testing.
This guide walks you through two different approaches you can follow when backing up and
restoring MongoDB deployments on Kubernetes:
Back up the data from the source deployment and restore it in a new deployment using
MongoDB's built-in backup/restore tools.
Back up the persistent volumes from the source deployment and attach them to a new
deployment using Velero, a Kubernetes backup/restore tool.
You have two separate Kubernetes clusters - a source cluster and a destination cluster - with
kubectl and Helm v3 installed. This guide uses Google Kubernetes Engine (GKE) clusters
but you can also use any other Kubernetes provider. Learn how to install kubectl and Helm
v3.x.
You have configured Helm to use the Tanzu Application Catalog chart repository following
the instructions for Tanzu Application Catalog or the instructions for VMware Tanzu
Application Catalog for Tanzu Advanced.
You have previously deployed the Tanzu Application Catalog MongoDB Helm chart with
replication on the source cluster and added some data to it. Example command sequences
to perform these tasks are shown below, where the PASSWORD placeholder refers to the
database administrator password. Replace the REPOSITORY and REGISTRY placeholders
with references to your Tanzu Application Catalog chart repository and container registry.
--namespace default \
--set replicaSet.enabled=true \
--set mongodbRootPassword=PASSWORD
kubectl run --namespace default mongodb-client --rm --tty -i --restart='Never'
--image REGISTRY/mongodb:4.2.5-debian-10-r35 --command -- mongo admin --host mo
ngodb --authenticationDatabase admin -u root -p PASSWORD
use mydb
db.accounts.insert({name:"john", total: "1058"})
db.accounts.insert({name:"jane", total: "6283"})
db.accounts.insert({name:"james", total: "472"})
exit
2. Forward the MongoDB service port and place the process in the background:
3. Create a directory for the backup files and make it the current working directory:
mkdir mybackup
chmod o+w mybackup
cd mybackup
4. Back up the contents of all the databases to the current directory using the mongodump tool. If
this tool is not installed on your system, use Tanzu Application Catalog's MongoDB Docker
image to perform the backup, as shown below (replace the REGISTRY placeholder with your
Tanzu Application Catalog container registry):
Here, the --net parameter lets the Docker container use the host's network stack and
thereby gain access to the forwarded port. The mongodump command connects to the
MongoDB service and creates backup files in the /app directory, which is mapped to the
current directory (mybackup/) on the Docker host with the -v parameter. Finally, the --rm
parameter deletes the container after the mongodump command completes execution.
5. Stop the service port forwarding by terminating the corresponding background process.
At the end of this step, the backup directory should contain the data from your running MongoDB
deployment.
1. Create a new MongoDB deployment. Replace the PASSWORD placeholder with the
database administrator password and the REPOSITORY placeholder with a reference to your
Tanzu Application Catalog chart repository.
2. Create an environment variable with the password for the new deployment:
3. Forward the MongoDB service port for the new deployment and place the process in the
background:
4. Restore the contents of the backup into the new release using the mongorestore tool. If this
tool is not available on your system, mount the directory containing the backup files as a
volume in Tanzu Application Catalog's MongoDB Docker container and use the mongorestore
client tool in the container image to import the backup into the new cluster, as shown below
(replace the REGISTRY placeholder with your Tanzu Application Catalog container registry):
cd mybackup
docker run --rm --name mongodb -v $(pwd):/app --net="host" REGISTRY/mongodb:lat
est mongorestore -u root -p $MONGODB_ROOT_PASSWORD /app
Here, the -v parameter mounts the current directory (containing the backup files) to the container's
/app path. Then, the mongorestore client tool is used to connect to the new MongoDB service and
restore the data from the original deployment. As before, the --rm parameter destroys the container
after the command completes execution.
2. Connect to the new deployment and confirm that your data has been successfully restore
(replace the REGISTRY placeholder with your Tanzu Application Catalog container registry):
Both clusters are on the same cloud provider, because Velero does not support the
migration of persistent volumes across cloud providers.
The restored deployment on the destination cluster will have the same name, namespace
and credentials as the original deployment on the source cluster.
NOTE
For persistent volume migration across cloud providers with Velero, you have the
option of using Velero's Restic integration. This integration is currently beta quality
and is not covered in this guide.
1. Modify your context to reflect the source cluster (if not already done).
2. Follow the Velero plugin setup instructions for your cloud provider. For example, if you are
using Google Cloud Platform (as this guide does), follow the GCP plugin setup instructions to
create a service account and storage bucket and obtain a credentials file.
3. Then, install Velero on the source cluster by executing the command below, remembering
to replace the BUCKET-NAME placeholder with the name of your storage bucket and the
SECRET-FILENAME placeholder with the path to your credentials file:
You should see output similar to the screenshot below as Velero is installed:
4. Confirm that the Velero deployment is successful by checking for a running pod using the
command below:
1. Create a backup of the volumes in the running MongoDB deployment on the source cluster.
This backup will contain both the primary and secondary node volumes.
2. Execute the command below to view the contents of the backup and confirm that it contains
all the required resources:
3. To avoid the backup data being overwritten, switch the bucket to read-only access:
2. Install Velero on the destination cluster as described in Step 1. Remember to use the same
values for the BUCKET-NAME and SECRET-FILENAME placeholders as you did originally, so
that Velero is able to access the previously-saved backups.
3. Confirm that the Velero deployment is successful by checking for a running pod using the
command below:
4. Restore the persistent volumes in the same namespace as the source cluster using Velero.
5. Confirm that the persistent volumes have been restored and note the volume name for the
primary node:
6. Delete the persistent volume corresponding to the secondary node and retain only the
volume corresponding to the primary node. If there is more than one secondary volume
(depending on how you originally deployed the chart), delete all the secondary volumes.
7. Create a new MongoDB deployment. Use the same name and namespace as the original
deployment and use the chart's persistence.existingClaim parameter to attach the existing
volume. Replace the PASSWORD placeholder with the same database administrative
password used in the original release, the PRIMARY-PVC-NAME placeholder with the name
of the restored primary node volume, the REPLICASET-KEY with the key obtained at the
end of the previous step and the REPOSITORY placeholder with a reference to your Tanzu
Application Catalog chart repository.
NOTE: It is important to create the new deployment on the destination cluster using the
same namespace, deployment name, credentials and replicaset key as the original
This will create a new deployment that uses the original primary node volume (and hence the
original data). Note that if replication is enabled, as in the example above, installing the chart
will automatically create a new volume for each secondary node.
8. Connect to the new deployment and confirm that your original data is intact (replace the
REGISTRY placeholder with your Tanzu Application Catalog container registry):
Useful links
Tanzu Application Catalog MongoDB Helm chart
Velero documentation
Introduction
MariaDB Galera Cluster makes it easy to create a high-availability database cluster with synchronous
replication while still retaining all the familiar MariaDB clients and tools. VMware Tanzu Application
Catalog (Tanzu Application Catalog) offers a MariaDB Galera Helm chart that makes it quick and easy
to deploy such a cluster on Kubernetes. This Helm chart is compliant with current best practices and
can also be easily upgraded to ensure that you always have the latest fixes and security updates.
Once you have a MariaDB Galera Cluster deployed, you need to start thinking about ongoing
maintenance and disaster recovery, and begin putting a data backup/restore strategy in place. This
backup/restore strategy is needed for many operational scenarios, including disaster recovery
planning, off-site data analysis or application load testing.
This guide walks you through two different approaches you can follow when backing up and
restoring MariaDB Galera Cluster deployments on Kubernetes:
Back up the data from the source deployment and restore it in a new deployment using
MariaDB's built-in backup/restore tools.
Back up the persistent volumes from the source deployment and attach them to a new
deployment using Velero, a Kubernetes backup/restore tool.
You have two separate Kubernetes clusters - a source cluster and a destination cluster - with
kubectl and Helm v3 installed. This guide uses Google Kubernetes Engine (GKE) clusters
but you can also use any other Kubernetes provider. Learn how to install kubectl and Helm
v3.x.
You have configured Helm to use the Tanzu Application Catalog chart repository following
the instructions for Tanzu Application Catalog or the instructions for VMware Tanzu
Application Catalog for Tanzu Advanced.
You have previously deployed the Tanzu Application Catalog MariaDB Galera Helm chart on
the source cluster and added some data to it. Example command sequences to perform
these tasks are shown below, where the PASSWORD and REPL-PASSWORD placeholders
refer to the database administrator and replication user passwords respectively. Replace the
REPOSITORY and REGISTRY placeholders with references to your Tanzu Application
Catalog chart repository and container registry respectively.
2. Forward the MariaDB Galera Cluster service port and place the process in the background:
3. Create a directory for the backup files and make it the current working directory:
mkdir mybackup
cd mybackup
4. Back up the contents of all the databases to the current directory using the mysqldump tool. If
this tool is not installed on your system, use Tanzu Application Catalog's MariaDB Galera
Docker image to perform the backup, as shown below. Replace the PASSWORD
placeholder with the database administrator password and the REGISTRY placeholder with a
reference to your Tanzu Application Catalog container registry.
Here, the --net parameter lets the Docker container use the host's network stack and
thereby gain access to the forwarded port. The mysqldump command connects to the
forwarded MariaDB Galera service and creates an SQL backup file in the /app directory,
which is mapped to the current directory (mybackup/) on the Docker host. Finally, the --rm
parameter deletes the container after the mysqldump command completes execution.
5. Stop the service port forwarding by terminating the corresponding background process.
At the end of this step, the backup directory should contain a file with the data from your running
MariaDB Galera Cluster deployment.
1. Create a new MariaDB Galera Cluster deployment. Replace the PASSWORD, REPL-
PASSWORD and REPOSITORY placeholders with the database administrator password,
replication user password and a reference to your Tanzu Application Catalog chart repository.
NOTE: If using Tanzu Application Catalog for Tanzu Advanced, install the chart following the
steps described in the VMware Tanzu Application Catalog for Tanzu Advanced
documentation instead.
2. Forward the MariaDB Galera Cluster service port for the new deployment and place the
process in the background:
3. Create and start a Tanzu Application Catalog MariaDB Galera container image. Mount the
directory containing the backup file as a volume in this container and use the mysql client
tool in the container image to import the backup into the new cluster, as shown below.
Replace the PASSWORD placeholder with the database administrator password and the
REGISTRY placeholder with a reference to your Tanzu Application Catalog container registry.
cd mybackup
docker create -t --rm --name galera-client -v $(pwd):/app --net="host" REGISTRY
/mariadb-galera:latest bash
docker start galera-client
docker exec -i galera-client mysql -h 127.0.0.1 -uroot -pPASSWORD < backup.sql
Here, the -v parameter mounts the current directory (containing the backup file) to the
container's /app path. Then, the mysql client tool is used to connect to the new MariaDB
Galera Cluster service and restore the data from the original deployment. The --rm
parameter destroys the container on exit.
5. Connect to the new deployment and confirm that your data has been successfully restored.
Replace the PASSWORD placeholder with the database administrator password and the
REGISTRY placeholder with a reference to your Tanzu Application Catalog container registry.
Both clusters are on the same cloud provider, because Velero does not support the
migration of persistent volumes across cloud providers.
The restored deployment on the destination cluster will have the same name, namespace
and credentials as the original deployment on the source cluster.
NOTE
This approach requires scaling the cluster down to a single node to perform the
backup.
NOTE
For persistent volume migration across cloud providers with Velero, you have the
option of using Velero's Restic integration. This integration is currently beta quality
and is not covered in this guide.
1. Modify your context to reflect the source cluster (if not already done).
2. Follow the Velero plugin setup instructions for your cloud provider. For example, if you are
using Google Cloud Platform (as this guide does), follow the GCP plugin setup instructions to
create a service account and storage bucket and obtain a credentials file.
3. Then, install Velero on the source cluster by executing the command below, remembering
to replace the BUCKET-NAME placeholder with the name of your storage bucket and the
SECRET-FILENAME placeholder with the path to your credentials file:
You should see output similar to the screenshot below as Velero is installed:
4. Confirm that the Velero deployment is successful by checking for a running pod using the
command below:
2. Obtain the name of the running pod. Make a note of the node number which is suffixed to
the name. For example, if the running pod is galera-mariadb-galera-0, the node number is
0.
4. Execute the command below to view the contents of the backup and confirm that it contains
all the required resources:
5. To avoid the backup data being overwritten, switch the bucket to read-only access:
2. Install Velero on the destination cluster as described in Step 1. Remember to use the same
values for the BUCKET-NAME and SECRET-FILENAME placeholders as you did originally, so
that Velero is able to access the previously-saved backups.
3. Confirm that the Velero deployment is successful by checking for a running pod using the
command below:
4. Restore the persistent volumes in the same namespace as the source cluster using Velero.
6. Delete all the restored persistent volumes except the volume with number corresponding to
the running node number seen in Step 2. For example, if the node number noted in Step 2
is 0, delete all the persistent volumes except the volume named data-galera-mariadb-
galera-0.
7. Create a new MariaDB Galera Cluster deployment. Use the same name and namespace as
the original deployment. Replace the PASSWORD and REPL-PASSWORD placeholders with
the same database administrator and replication user passwords used in the original
deployment and the REPOSITORY placeholder with a reference to your Tanzu Application
Catalog chart repository.
NOTE: It is important to create the new deployment on the destination cluster using the
same namespace, deployment name and credentials as the original deployment on the
source cluster.
This will create a new deployment that bootstraps from the original node volume (and hence
the original data).
8. Connect to the new deployment and confirm that your data has been successfully restored.
Replace the PASSWORD placeholder with the database administrator password and the
REGISTRY placeholder with a reference to your Tanzu Application Catalog container registry.
Useful links
MariaDB Galera Helm chart
Velero documentation
Introduction
Redis is a popular open source in-memory data store with a number of advanced features for high
availability and data optimization. VMware Tanzu Application Catalog (Tanzu Application Catalog)
offers a Redis Cluster Helm chart which makes it quick and easy to deploy a Redis cluster with
sharding and multiple write points on Kubernetes. This Helm chart is compliant with current best
practices and can also be upgraded to ensure that you always have the latest fixes and security
updates.
Once you have your Redis cluster deployed on Kubernetes, it is essential to put a data backup
strategy in place to protect the data within it. This backup strategy is needed for many operational
scenarios, including disaster recovery planning, off-site data analysis or application load testing.
This guide walks you through the process of backing up and restoring a Redis cluster on Kubernetes
using Velero, a Kubernetes backup/restore tool.
You have two separate Kubernetes clusters - a source cluster and a destination cluster - with
kubectl and Helm v3 installed. This guide uses Google Kubernetes Engine (GKE) clusters
but you can also use any other Kubernetes provider. Learn how to install kubectl and Helm
v3.x.
You have configured Helm to use the Tanzu Application Catalog chart repository following
the instructions for Tanzu Application Catalog or the instructions for VMware Tanzu
Application Catalog for Tanzu Advanced.
You have previously deployed the Redis Cluster Helm chart on the source cluster and added
some data to it. Example command sequences to perform these tasks are shown below,
where the PASSWORD placeholder refers to the Redis password. Replace the REPOSITORY
and REGISTRY placeholders with references to your Tanzu Application Catalog chart
repository and container registry respectively.
exit
This method involves copying the persistent data volumes for the Redis Cluster nodes and reusing
them in a new deployment with Velero, an open source Kubernetes backup/restore tool. This
method is only suitable when:
Both clusters are on the same cloud provider, because Velero does not support the
migration of persistent volumes across cloud providers.
The restored deployment on the destination cluster will have the same name, namespace,
topology and credentials as the original deployment on the source cluster.
1. Modify your context to reflect the source cluster (if not already done).
2. Follow the Velero plugin setup instructions for your cloud provider. For example, if you are
using Google Cloud Platform (as this guide does), follow the GCP plugin setup instructions to
create a service account and storage bucket and obtain a credentials file.
3. Then, install Velero on the source cluster by executing the command below, remembering
to replace the BUCKET-NAME placeholder with the name of your storage bucket and the
SECRET-FILENAME placeholder with the path to your credentials file:
You should see output similar to the screenshot below as Velero is installed:
4. Confirm that the Velero deployment is successful by checking for a running pod using the
command below:
2. Execute the command below to view the contents of the backup and confirm that it contains
all the required resources:
3. To avoid the backup data being overwritten, switch the bucket to read-only access:
2. Install Velero on the destination cluster as described in Step 1. Remember to use the same
values for the BUCKET-NAME and SECRET-FILENAME placeholders as you did originally, so
that Velero is able to access the previously-saved backups.
3. Confirm that the Velero deployment is successful by checking for a running pod using the
command below:
4. Restore the persistent volumes in the same namespace as the source cluster using Velero.
6. Create a new Redis Cluster deployment. Use the same name, topology and namespace as
the original deployment. Replace the PASSWORD placeholder with the same password used
in the original deployment and the REPOSITORY placeholder with a reference to your Tanzu
NOTE: If using Tanzu Application Catalog for Tanzu Advanced, install the chart following the
steps described in the VMware Tanzu Application Catalog for Tanzu Advanced
documentation instead.
NOTE: It is important to create the new deployment on the destination cluster using the
same namespace, deployment name, topology and credentials as the original deployment on
the source cluster.
This will create a new deployment that uses the restored persistent volumes (and hence the
original data).
7. Connect to the new deployment and confirm that your data has been successfully restored.
Replace the PASSWORD placeholder with the correct password and the REGISTRY
placeholder with a reference to your Tanzu Application Catalog container registry.
Useful links
Redis Cluster Helm chart
Velero documentation
Introduction
RabbitMQ is a highly-scalable and reliable open source message broking system. It supports a
number of different messaging protocols, as well as message queueing and plugins for additional
customization.
VMware Tanzu Application Catalog's (Tanzu Application Catalog) RabbitMQ Helm chart makes it easy
to deploy a scalable RabbitMQ cluster on Kubernetes. This Helm chart is compliant with current best
practices and can also be easily upgraded to ensure that you always have the latest fixes and security
updates.
Once the RabbitMQ cluster is operational, backing up the data held within it becomes an important
and ongoing administrative task. A data backup/restore strategy is required not only for data security
and disaster recovery planning, but also for other tasks like off-site data analysis or application load
testing.
This guide explains how to back up and restore a RabbitMQ deployment on Kubernetes using
Velero, an open-source Kubernetes backup/restore tool.
You have two separate Kubernetes clusters - a source cluster and a destination cluster - with
kubectl and Helm v3 installed. This guide uses Google Kubernetes Engine (GKE) clusters
but you can also use any other Kubernetes provider. Learn how to install kubectl and Helm
v3.x.
You have configured Helm to use the Tanzu Application Catalog chart repository following
the instructions for Tanzu Application Catalog or the instructions for VMware Tanzu
Application Catalog for Tanzu Advanced.
You have previously deployed the Tanzu Application Catalog RabbitMQ Helm chart on the
source cluster and added some data to it. Example command sequences to perform these
tasks are shown below, where the PASSWORD placeholder refers to the administrator
password and the cluster is deployed with a single node. Replace the REPOSITORY
placeholder with a reference to your Tanzu Application Catalog chart repository.
Both clusters are on the same Kubernetes provider, as this is a requirement of Velero's
native support for migrating persistent volumes.
The restored deployment on the destination cluster will have the same name, namespace
and credentials as the original deployment on the source cluster.
NOTE
The procedure outlined in this guide can only be used to back up and restore
persistent messages in the source RabbitMQ cluster. Transient messages will not be
backed up or restored.
NOTE
For persistent volume migration across cloud providers with Velero, you have the
option of using Velero's Restic integration. This integration is not covered in this
guide.
1. Modify your context to reflect the source cluster (if not already done).
2. Follow the Velero plugin setup instructions for your cloud provider. For example, if you are
using Google Cloud Platform (as this guide does), follow the GCP plugin setup instructions to
create a service account and storage bucket and obtain a credentials file.
3. Then, install Velero on the source cluster by executing the command below, remembering
to replace the BUCKET-NAME placeholder with the name of your storage bucket and the
SECRET-FILENAME placeholder with the path to your credentials file:
You should see output similar to the screenshot below as Velero is installed:
4. Confirm that the Velero deployment is successful by checking for a running pod using the
command below:
1. Create a backup of the volumes in the running RabbitMQ deployment on the source cluster.
This backup will contain both the primary and secondary node volumes.
2. Execute the command below to view the contents of the backup and confirm that it contains
all the required resources:
3. To avoid the backup data being overwritten, switch the bucket to read-only access:
2. Install Velero on the destination cluster as described in Step 1. Remember to use the same
values for the BUCKET-NAME and SECRET-FILENAME placeholders as you did originally, so
that Velero is able to access the previously-saved backups.
3. Confirm that the Velero deployment is successful by checking for a running pod using the
command below:
4. Restore the persistent volumes in the same namespace as the source cluster using Velero.
6. Create a new RabbitMQ deployment. Use the same name, namespace and cluster topology
as the original deployment. Replace the PASSWORD placeholder with the same
administrator password used in the original deployment and the REPOSITORY placeholder
with a reference to your Tanzu Application Catalog chart repository.
NOTE: If using Tanzu Application Catalog for Tanzu Advanced, install the chart following the
steps described in the VMware Tanzu Application Catalog for Tanzu Advanced
documentation instead.
NOTE: The deployment command shown above is only an example. It is important to create
the new deployment on the destination cluster using the same namespace, deployment
name, credentials and cluster topology as the original deployment on the source cluster.
This will create a new deployment that uses the original pod volumes (and hence the original
data).
7. Connect to the new deployment and confirm that your original queues and messages are
intact using a query like the example shown below. Replace the PASSWORD placeholder
with the administrator password
Useful links
Velero documentation
Introduction
VMware Tanzu Application Catalog (Tanzu Application Catalog) offers Helm charts for popular
database solutions like MySQL, MariaDB and PostgreSQL. These charts let you deploy database
services on Kubernetes in a secure and reliable manner whilst also ensuring compliance with current
best practices. Tanzu Application Catalog's Helm charts can also be easily upgraded to ensure that
you always have the latest fixes and security updates.
As time passes, there may be situations where you need to migrate the data stored in these
database deployments to other clusters. For example, you might want to transfer a copy of your data
to a separate cluster for isolated integration testing or load testing. Or, you might want to experiment
with alpha Kubernetes features that are not yet available in production deployments.
Velero, combined with Tanzu Application Catalog's charts, offers one possible solution to this
migration problem. Many of Tanzu Application Catalog's Helm charts let you create new
deployments that make use of existing persistent volumes (PVCs). This means that you can use
Velero to backup and copy the persistent data volumes from your source cluster, and then use
Tanzu Application Catalog's Helm charts to create new deployments in your destination cluster using
the copied volumes.
You have two separate Kubernetes clusters - a source cluster and a destination cluster - with
kubectl and Helm v3 installed. This guide uses Google Kubernetes Engine (GKE) clusters
but you can also use any other Kubernetes provider. Learn how to install kubectl and Helm
v3.x.
You have configured Helm to use the Tanzu Application Catalog chart repository following
the instructions for Tanzu Application Catalog or the instructions for VMware Tanzu
Application Catalog for Tanzu Advanced.
Both clusters are on the same cloud provider, because Velero does not support the
migration of persistent volumes across cloud providers.
This guide walks you through the process of migrating a PostgreSQL database from one cluster to
another using Velero and VMware Application Catalog's PostgreSQL Helm chart. The steps
described will also work with other VMware Application Catalog charts that support using existing
persistent volumes.
NOTE
1. Deploy PostgreSQL on the source cluster. Replace the PASSWORD placeholder with a
password for your PostgreSQL deployment and REPOSITORY placeholder with a reference
to your VMware Application Catalog chart repository.
2. Wait for the deployment to complete and then use the commands below to connect to the
database service. Replace the REGISTRY placeholder with a reference to your VMware
Application Catalog container registry.
3. At the command prompt, create an empty database and table and enter some dummy
records into it
1. Follow the plugin setup instructions for your cloud provider. For example, if you are using
Google Cloud Platform (as this guide does), follow the GCP plugin setup instructions to create
a service account and storage bucket and obtain a credentials file.
2. Then, install Velero by executing the command below, remembering to replace the
BUCKET-NAME placeholder with the name of your storage bucket and the SECRET-
FILENAME placeholder with the path to your credentials file:
You should see output similar to the screenshot below as Velero is installed:
1. Confirm that the Velero deployment is successful by checking for a running pod using the
command below:
TIP: The previous command uses additional resource and label selectors to backup only the PVCs
related to the PostgreSQL deployment. Optionally, you can backup all deployments in a specific
namespace with the --include-namespaces parameter, or backup the entire cluster by omitting all
selectors.
Execute the command below to view the contents of the backup and confirm that it contains all the
required resources:
2. Install Velero on the destination cluster as described in Step 2. Remember to use the same
values for the BUCKET-NAME and SECRET-FILENAME placeholders as you did originally, so
that Velero is able to access the previously-saved backups.
3. Confirm that the Velero deployment is successful by checking for a running pod using the
command below:
4. To avoid the backup data being overwritten, switch the bucket to read-only access:
6. Restore the backed-up volumes. Note that this may take a few minutes to complete.
7. Confirm that the persistent volumes have been restored on the destination cluster and note
the PVC name:
2. Wait until the deployment is complete. Once the deployment is complete, log in to the
PostgreSQL console and confirm that your original data has been successfully migrated. Use
the commands below and confirm that you see output similar to that shown in the
screenshot.
At this point, you have successfully migrated your database content using Velero.
Useful links
To learn more about the topics discussed in this guide, use the links below:
Velero documentation