This project illustrates the end-to-end stand up of the MARA project using Pulumi. It is intended to be used as a reference when building your own Infrastructure as Code (IaC) deployments. As such, each discrete stage of deployment is defined as a separate Pulumi project that can be deployed independently of each stage. Although Pulumi supports many programming languages, Python was chosen as the language for this project. The reimplementation of the deployment here should be easily reproducible in other languages.
For instructions on running the project, refer to the Getting Started Guide.
Several directories, located at the root of the project, are used. These are at the project root because they are intended to be outside the specific IaC providers (e.g., to be used for a port to Terraform).
├── bin
├── config
│ └── pulumi
├── docker
├── docs
└── extras
- The
bin
directory contains all the binaries and scripts that are used to start/stop the project and provide additional capabilities. - The
config/pulumi
directory holds the configuration files for deployments, as well as a reference configuration that illustrates the available configuration options and their defaults. - The
docker
directory contains Dockerfiles and a script to build a Docker-based deployment image that contains all the tooling necessary to deploy MARA. - The
docs
directory contains all documentation relevant to the overall project. - The
extras
directory contains additional scripts, notes, and configurations.
This directory contains all Pulumi/Python-based logic, which currently consists of the following:
├── automation
│ └── providers
├── config
├── infrastructure
│ ├── aws
│ ├── digitalocean
│ ├── kubeconfig
│ └── linode
├── kubernetes
│ ├── applications
│ ├── certmgr
│ ├── logagent
│ ├── logstore
│ ├── nginx
│ ├── observability
│ ├── prometheus
│ └── secrets
├── tools
│ ├── common
│ ├── metallb
│ └── nfsvolumes
└── utility
├── kic-image-build
├── kic-image-push
└── kic-pulumi-utils
- The
automation
directory contains the files used to interface with the pulumi automation api, including provider-specific files. - The
config
directory contains files used by Pulumi to manage the configuration for this project. Note that this directory is essentially a redirect to the project-wideconfig
directory. - The
infrastructure
directory contains files used to stand up Kubernetes as well as to provide a common project for the infrastructure and kubeconfig-based clusters. - The
kubernetes
directory contains the Kubernetes-based deployments. There are two key subdirectories in this directory:- The
nginx
directory contains all NGINX products. - The
secrets
directory contains all encrypted secrets. - The
applications
directory contains all applications that have been tested for deployment with MARA.
- The
- The
tools
directory contains extra tooling for specific use cases. - The
utility
directory contains the code used to build/pull/push KIC, and other projects used to support the environment. - The
venv/bin
directory contains the virtual environment for Python along with some key utilities, such aspulumi
,kubectl
, andnode
.
The Pulumi configuration files are in the config
directory. Pulumi's configuration files use the following naming convention:
Pulumi.<stackname>.yaml
. To create a new configuration file for your Pulumi
stack, create a new file with a name that includes the stack name. Then, refer
to the sample
configuration file
for configuration entries that you want to customize and copy over the entries
that you want to modify from their defaults.
The following directories are specific to AWS.
Contained within the vpc
directory is the first
Pulumi project which is responsible for setting up the VPC and subnets used by
EKS. The project is built so that it will attempt to create a subnet for each
availability zone within the running region. You may want to customize this
behavior, or the IP addressing scheme used.
Located within the eks
directory is a project
used to stand up a new EKS cluster on AWS. This project reads data from the
previously executed VPC project using its VPC id and subnets. In this project
you may want to customize the instance_type
, min_size
, or max_size
parameters provided to the cluster.
The ecr
project is responsible for installing and
configuring ECR for use with the previously created EKS cluster.
The following directories are specific to Digital Ocean.
Contained within the domk8s
directory
contains the logic needed to stand up a Digital Ocean Managed Kubernetes
cluster. There are a number of configuration options available to customize the
build, however the defaults can be used to create a standard sized cluster in
the SFO3 region.
These directories contain the projects required to create and use the Digital Ocean container registry.
This directory contains the project required to provision a DNS record for the Digital Ocean egress.
The following directories are specific to Linode.
Contained within the lke
directory contains
the logic needed to stand up a Linode Kubernetes Engine cluster. There are a
number of configuration options available to customize the build.
These directories contain the projects required to create and use the Harbor container registry with the Linode deployment.
Within the kic-image-build
directory, there is
a Pulumi project that will allow you to build a new KIC from source. Download
of source, compilation, and image creation are fully automated. This project
can be customized to build different flavors of KIC.
Within the kic-image-push
directory, there is a
Pulumi project that will allow you to push the previously created KIC Docker
image to ECR in a fully automated manner.
In the ingress-contoller
directory,
you will find the Pulumi project responsible for installing NGINX KIC. You may
want to customize this project to allow for deploying different versions of
KIC. This chart is only used for AWS deployments. All other deployments use the
ingress-controller- repo-only
directory, which at this time only allows the use of deployments from the
NGINX repo - either NGINX IC or NGINX Plus IC (with a JWT).
A sample config-map is provided in the Pulumi deployment code. This code will adjust the logging format to approximate the upstream NGINX KIC project which will allow for easier ingestion into log storage and processing systems.
Note: This deployment uses the GA Ingress APIs. This has been tested with helm chart version 0.11.1 and NGINX KIC 2.0.2. Older versions of the KIC and helm charts can be used, but care should be taken to ensure that the helm chart version used is compatible with the KIC version. This information can be found in the NGINX KIC Release Notes for each release.
Starting with Kubernetes version 1.22, support for the Ingress Beta API
networking.k8s.io/v1beta
will be dropped, requiring use of the GA Ingress API
networking.k8s.io/v1
. However, Kubernetes versions 1.19 through 1.21 allows
these two API versions to coexist and maintains compatibility for consumers of
the API – meaning, the API will respond correctly to calls to either the
v1beta
and/or v1
routes.
This project uses the NGINX KIC v2.x releases which includes full support for the GA APIs.
In the logstore
directory, you will find the Pulumi
project responsible for installing your log store. The current solution deploys
Elasticsearch and Kibana
using the
Bitnami Elasticsearch
chart. This solution can be swapped for other options as desired. This
application is deployed to the logstore
namespace. There are several
configuration options available in the configuration file for the project in order
to better tailor this deployment to the size of the cluster being used.
To access the Kibana dashboard via your web browser, you will need to set up
port forwarding for the kibana pod. This can be accomplished using the
kubectl
command:
$ # Find the Kibana pod name
$ kubectl get pods -n logstore
NAME READY STATUS RESTARTS AGE
elastic-coordinating-only-b76674c4c-d58rh 1/1 Running 0 61m
elastic-coordinating-only-b76674c4c-sb6v7 1/1 Running 0 61m
elastic-elasticsearch-data-0 1/1 Running 0 61m
elastic-elasticsearch-data-1 1/1 Running 0 61m
elastic-elasticsearch-ingest-589d4ddf4b-6djjz 1/1 Running 0 61m
elastic-elasticsearch-ingest-589d4ddf4b-6mzmb 1/1 Running 0 61m
elastic-elasticsearch-master-0 1/1 Running 0 61m
elastic-elasticsearch-master-1 1/1 Running 0 61m
elastic-kibana-d45db8647-ghhx2 1/1 Running 0 61m
$ # Setup the port forward
$ kubectl port-forward elastic-kibana-d45db8647-ghhx2 5601:5601 -n logstore
Forwarding from 127.0.0.1:5601 -> 5601
Forwarding from [::1]:5601 -> 5601
Handling connection for 5601
In the logagent
directory, you will find the Pulumi project
responsible for installing your log agent. The current solution deploys
Filebeat
, which connects to the logstore
deployed in the previous step. This solution can be swapped for other options
as desired. This application is deployed to the logagent
namespace.
TLS is enabled via cert-manager, which is installed in the cert-manager namespace. Creation of ClusterIssuer or Issuer resources is delegated to the individual applications and is not done as part of this deployment.
Prometheus is deployed and configured to enable the collection of metrics for all components that have a defined service monitor. At installation time, the deployment will instantiate:
- Node Exporters
- Kubernetes Service Monitors
- Grafana preloaded with dashboards and datasources for Kubernetes management
- The NGINX Ingress Controller
- Statsd receiver
The former behavior of using the prometheus.io:scrape: true
property set in
annotations indicating pods (where metrics should be scraped) has been
deprecated, and these annotations will be removed in the near future.
Also, the standalone Grafana deployment has been removed from the standard deployment scripts, as it is installed as part of this project.
Finally, this namespace will hold service monitors created by other projects. For example, the Bank of Sirius deployment currently deploys a service monitor for each of the postgres monitors that are deployed.
Notes:
- The KIC needs to be configured to expose Prometheus metrics. This is currently done by default.
- The default address binding of the
kube-proxy
component is set to127.0.0.1
and therefore will cause errors when the canned Prometheus scrape configurations are run. The fix is to set this address to0.0.0.0
. An example manifest has been provided in prometheus/extras that can be applied against your installation withkubectl apply -f ./filename
. Please only apply this change once you have verified that it will work with your version of Kubernetes. - The grafana namespace has been maintained in the configuration file to be used by the Prometheus operator-deployed version of Grafana. This version only accepts a password – you can still specify a username for the admin account but it will be silently ignored. This will be changed in the future.
We deploy the OTEL Collector Operator along with a simple collector. There are several other configurations in the observability/otel-objects directory. See the README.md file in the observability/otel-objects for more information, including an explanation of the default configuration.
A forked version of the Google
Bank of Anthos
application is contained in the sirius
directory. The github repository for this for is at
Bank of Sirius.
Normally, the frontend
microservice is exposed via a load balancer
for traffic management. This deployment has been modified to use the NGINX
or NGINX Plus KIC to manage traffic to the frontend
microservice. The NGINX
or NGINX Plus KIC is integrated into the cluster logging system, and the user
can configure the KIC as desired.
An additional change to the application is the conversion of several of the standard Kubernetes deployment manifests into Pulumi code. This has been done for the configuration maps, the ingress controller, and the JWT RSA signing key pair. This allows the user to take advantage Pulumi's feature set, by demonstrating the process of creating and deploying an RSA key pair at deployment time and using the project configuration file to set config variables, including secrets.
As part of the Bank of Sirius deployment, we deploy a cluster-wide self-signed issuer using the cert-manager deployed above. This is then used by the ingress object created to enable TLS access to the application. Note that this issuer can be changed out by the user, for example to use the ACME issuer. The use of the ACME issuer has been tested and works without issues, provided the FQDN meets the length requirements. As of this writing, the AWS ELB hostname is too long to work with the ACME server. Additional work in this area will be undertaken to provide dynamic DNS record creation as part of this process so legitimate certificates can be issued.
To provide visibility into the Postgres databases that are running as part of the application, the Prometheus Postgres data exporter will be deployed into the same namespace as the application and will be configured to be scraped by the Prometheus server installed earlier.
Note: Due to the way that Pulumi currently handles secrets, the secrets directory contains its own configuration directory secrets/config. This directory contains an example configuration file that can be copied over and used. The user will be prompted to add passwords to the configuration file at the first run of the startup process.
To help enable simple load testing, a script has been provided that uses the
kubectl
command to port-forward monitoring and management connections
to the local workstation. This command is
test-foward.sh
.