Welcome to the APAC Services Hands on Training session.
👉 Ensure you can login to your Dynatrace Managed tenant
👉 Ensure you can SSH into your VM.
👉 Ensure you can reach: http://52.200.197.144.nip.io/p/mac
👉 Once logged in. Go to Settings > Integration > Dynatrace API > Token Settings
and enable the new API format.
👉 Generate an API Token with the following permissions:
New API Key format: Good article from Barbara Schachner
I have created an auto-tag
called myFirstTag
. Please help me retrieve the JSON representation of this tag.
The Dynatrace customer you've been assigned to sells SaaS to their end customers. Currently they have 3 customers: Customer A
, Customer B
and Customer C
.
Your customer is currently running on AWS but they have plans to extend their service to Azure and / or GCP in the near future.
Your customer is planning a large marketing event in just over 1 month. They expect to have over 1000 customers within the first few months.
Your customer would like to use a single monitoring tool (Dynatrace) to monitor the health of their entire customer environment. They need to see statistics, health and metrics of individual customers views in addition to a "global" health dashboard for all customers.
Your job is to help them achieve this goal. You have less than 1 month to deliver this outcome.
Each participant should have received access to a Dynatrace environment. In this environment you'll find a single host connected.
You've received the following architecture diagram from your customer.
http://staging.customera.VMIP.nip.io
http://customera.VMIP.nip.io
http://staging.customerb.VMIP.nip.io
http://customerb.VMIP.nip.io
http://staging.customerc.VMIP.nip.io
http://customerc.VMIP.nip.io
👁️ Take 10 minutes and use the chat box to discuss with colleagues:
👁️ Has anyone delivered Dynatrace configuration as code to your customers? What was involved?
We will deliver all of this configuration to the customer as code.
The customer can then:
Dynatrace can then:
Due to the scale that this customer expects, every configuration we deliver must be automated. That said, we can build the template manually then use automation to build subsequent configuration.
Monaco is an open source project from Dynatrace to apply Monitoring As Code at scale.
The monaco
tool is idempotent. It will only make changes if required. Re-run as many times as you wish.
The monaco
binary is already available on the VM as ./monaco
so either run it from the VM or download the Windows binary and run it locally. Your choice.
Go to https://github.com/dynatrace-oss/dynatrace-monitoring-as-code/releases
and download the latest monaco
release for your operating system.
For ease during this demo, please rename the binary to ./monaco
(if on windows) or monaco
if on macOS or linux.
monaco
binary into this directoryprojects
environments.yaml
You should now have:
monaco
binarymonaco
binary called projects
monaco
binary called environments.yaml
Open environments.yaml
and type the following:
mac_training_environment:
- name: "mac_training_environment"
- env-url: "{{ .Env.MAC_TRAINING_ENVIRONMENT }}"
- env-token-name: "TOKEN_MAC_TRAINING_ENVIRONMENT"
Open a new command window and set your Dynatrace URL as an environment variable.
Notice that the name of this variable matches the env-url
variable you used in environments.yaml
set MAC_TRAINING_ENVIRONMENT=https://dtmanaged.dynatrace.training/e/***
Repeat the process by setting your API token. Again notice that the name corresponds to the value used in environments.yaml
:
set TOKEN_MAC_TRAINING_ENVIRONMENT=***
In the same command window, run monaco
:
./monaco --environments=environments.yaml --dry-run
You should see:
> ./monaco --environments=environments.yaml --dry-run
INFO Dynatrace Monitoring as Code v1.0.1
INFO Executing projects in this order:
INFO Processing environment mac_training_environment...
INFO Validation finished without errors
Monaco has the following concepts:
Environments are simply Dynatrace environments, SaaS or Managed. monaco
can push configuration to one or more environments.
As we've already seen, environments are defined in environments.yaml
.
Projects are distinct units of configuration. The most basic is to create a single project which holds your configuration. You can then push this identical configuration out to one (or multiple) environments.
Projects are created by creating a new folder inside the projects
folder.
A single configuration item in Dynatrace. The monaco
tool currently supports the following configuration types:
✅ This has already been configured in your demo environments.
The customer has already annotated their Deployment
with the following labels which we can leverage automatically in Dynatrace.
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: prod-web
namespace: customer-a
labels:
app: web
stage: prod
This is simple, give the default
service account permission to view metadata about the customer-a
, customer-b
and customer-c
namespaces.
kubectl -n customer-a create rolebinding default-view --clusterrole=view --serviceaccount=customer-a:default
kubectl -n customer-b create rolebinding default-view --clusterrole=view --serviceaccount=customer-b:default
kubectl -n customer-c create rolebinding default-view --clusterrole=view --serviceaccount=customer-c:default
Recall that your client creates a new namespace for each of their customers.
👉 Create an auto-tag rule via the UI which matches this definition:
Use the Dynatrace API to retrieve the JSON representation of that tag.
Use the Automatically Applied Tags
endpoint in the Configuration Api
to GET
all tag IDs:
{
"values": [{
"id": "afd026e7-2abc-492f-873e-66bb571a572a",
"name": "customer"
}]
}
Use the other GET
endpoint by passing this ID to retrieve the full JSON.
GET /api/config/v1/autoTags/afd026e7-2abc-492f-873e-66bb571a572a
Save this JSON as a file.
👉 Inside projects
, create a folder called baseconfig
. This folder will hold all of our configuration.
Inside projects/baseconfig
, create a new folder called auto-tag
.
Inside each configuration type folder you need one YAML file and one (or more) JSON files.
Every configuration needs a YAML containing required and optional content.
A minimal viable config looks like this:
config:
- {config name} : "{path of config json template}"
{config name}:
- name: "{a unique name}"
The JSON file(s) inside this folder essentially hold the content that you'd normally POST
to Dynatrace.
The only difference is that you can use variables inside the JSON which reference the YAML file.
Let's see that in action...
Create projects/baseconfig/auto-tag/tags.yaml
:
config:
- customer_tag: "customertag.json"
customer_tag:
- name: "customer"
Create projects/baseconfig/auto-tag/customertag.json
Paste in the JSON content that you retrieved from the Dynatrace API.
There are a few sections we don't need in customertag.json
.
Remove the metadata
section and id
variable. Your JSON should now look like this:
{
"name": "customer",
"rules": [
{
"type": "PROCESS_GROUP",
"enabled": true,
"valueFormat": "{ProcessGroup:KubernetesNamespace}",
"propagationTypes": [
"PROCESS_GROUP_TO_SERVICE"
],
"conditions": [
{
"key": {
"attribute": "PROCESS_GROUP_PREDEFINED_METADATA",
"dynamicKey": "KUBERNETES_NAMESPACE",
"type": "PROCESS_PREDEFINED_METADATA_KEY"
},
"comparisonInfo": {
"type": "STRING",
"operator": "EXISTS",
"value": null,
"negate": false,
"caseSensitive": null
}
}
]
}
]
}
Notice that we have certain hard coded values in the JSON. We can template these.
Templates in monaco
are denoted with double curly braces.
Replace customer
with {{ .name }}
:
{
"name": "{{ .name }}",
"rules": [...]
...
}
When monaco
executes, it will look at each configuration in the YAML and process them sequentially. We have one configuration:
- customer_tag: "customertag.json"
monaco
then looks at the JSON and the properties for customer_tag
. The properties are:
customer_tag:
- name: "customer"
monaco
replaces anything inside curly braces with the corresponding value (denoted by .VariableName
).
In this way, "{{ .name }}"
becomes "customer"
.
Delete any previous tag rules you have in the tenant.
Apply your configuration:
./monaco --environments=environments.yaml
You should see that one configuration has been applied:
./monaco --environments=environments.yaml
INFO Dynatrace Monitoring as Code v1.0.1
INFO Executing projects in this order:
INFO 1: projects\baseconfig (1 configs)
INFO Processing environment mac_training_environment...
INFO Processing project projects\baseconfig...
INFO Deployment finished without errors
We need a way to quickly distinguish the processes (pods) for each customer. This configuration will prepend the namespace
(aka customer name) to the process group.
Go to Settings > Processes and containers > Process group naming
. Add a new rule:
Name format is: {ProcessGroup:KubernetesNamespace} - {ProcessGroup:DetectedName}
Hint: Dynatrace API > Configuration API > Conditional Naming
{
"values": [{
"id": "c6e41ebd-726a-4d79-9fd6-d3bcc37b836b",
"name": "Prepend Customer Name to PG"
}]
}
{
"metadata": {
"configurationVersions": [
0
],
"clusterVersion": "1.206.95.20201116-094826"
},
"id": "c6e41ebd-726a-4d79-9fd6-d3bcc37b836b",
"type": "PROCESS_GROUP",
"nameFormat": "{ProcessGroup:KubernetesNamespace} - {ProcessGroup:DetectedName}",
"displayName": "Prepend Customer Name to PG",
"enabled": true,
"rules": [
{
"key": {
"attribute": "PROCESS_GROUP_PREDEFINED_METADATA",
"dynamicKey": "KUBERNETES_NAMESPACE",
"type": "PROCESS_PREDEFINED_METADATA_KEY"
},
"comparisonInfo": {
"type": "STRING",
"operator": "EXISTS",
"value": null,
"negate": false,
"caseSensitive": null
}
}
]
}
Remove metadata
and id
. Use variables in JSON.
{
"type": "PROCESS_GROUP",
"nameFormat": "{ProcessGroup:KubernetesNamespace} - {ProcessGroup:DetectedName}",
"displayName": "{{ .name }}",
"enabled": true,
"rules": [{
"key": {
"attribute": "PROCESS_GROUP_PREDEFINED_METADATA",
"dynamicKey": "KUBERNETES_NAMESPACE",
"type": "PROCESS_PREDEFINED_METADATA_KEY"
},
"comparisonInfo": {
"type": "STRING",
"operator": "EXISTS",
"value": null,
"negate": false,
"caseSensitive": null
}
}]
}
projects/baseconfig/conditional-naming-processgroup
rules.yaml
prepend-customer-name.json
config:
- prepend_customer_name: "prepend-customer-name.json"
prepend_customer_name:
- name: "Prepend Customer Name to PG"
prepend-customer-name.json
should have this content:
{
"type": "PROCESS_GROUP",
"nameFormat": "{ProcessGroup:KubernetesNamespace} - {ProcessGroup:DetectedName}",
"displayName": "{{ .name }}",
"enabled": true,
"rules": [{
"key": {
"attribute": "PROCESS_GROUP_PREDEFINED_METADATA",
"dynamicKey": "KUBERNETES_NAMESPACE",
"type": "PROCESS_PREDEFINED_METADATA_KEY"
},
"comparisonInfo": {
"type": "STRING",
"operator": "EXISTS",
"value": null,
"negate": false,
"caseSensitive": null
}
}]
}
Delete the manually created process group naming rule from the Dynatrace UI.
Run monaco with the --dry-run
flag to check for syntax errors:
./monaco --environments=environments.yaml --dry-run
When satisfied, run without the --dry-run
flag to push your new config:
./monaco --environments=environments.yaml
Notice there are now two configurations applied:
./monaco --environments=environments.yaml
INFO Dynatrace Monitoring as Code v1.0.1
INFO Executing projects in this order:
INFO 1: projects\baseconfig (2 configs)
INFO Processing environment mac_training_environment...
INFO Processing project projects\baseconfig...
INFO Deployment finished without errors
For fun, run the monaco tool again as many times as you wish. Notice it is perfectly safe.
Build configuration to prepend the customer name to the service
.
Hints:
conditional-naming-service
We have now built the following:
We have 6 websites:
Basic XHR detection and JQuery support should be enabled by default for all websites. Customer wants 20%
of traffic to be captured in staging
environments and 100%
capture in production
.
👉 Use the monaco
tool to define applications for each of these websites.
application
123
should be "123"
⚠️ Do not define the application URL rules yet, we'll do that together next.
Time: 10 minutes
Your customer made a mistake! Their clients are paying for Dynatrace and some have complained that they're not seeing all their visits.
They should actually be capturing the following traffic amounts for each customer:
👉 Please correct the traffic capture levels for your customer using monaco
.
Time: 5 minutes
Time to apply URL rules to the applications. So far we've dealt with configurations that stand alone. They do not reference, depend on or relate to any other configurations.
URL rules relate to the application for which they're assigned. So we have this:
Customer A - Staging | http://staging.customera |
Customer B - Staging | http://staging.customerb |
Customer C - Staging | http://staging.customerc |
Customer A - Production | http://customera |
Customer B - Production | http://customerb |
Customer C - Production | http://customerc |
projects/baseconfig/app-detection-rule
config:
- customer-a-staging: "rule.json"
- customer-a-production: "rule.json"
- customer-b-staging: "rule.json"
- customer-b-production: "rule.json"
- customer-c-staging: "rule.json"
- customer-c-production: "rule.json"
customer-a-staging:
- name: "/projects/baseconfig/application/customer-a-staging.name"
- application_id: "/projects/baseconfig/application/customer-a-staging.id"
- pattern: "http://staging.customera"
customer-b-staging:
- name: "/projects/baseconfig/application/customer-b-staging.name"
- application_id: "/projects/baseconfig/application/customer-b-staging.id"
- pattern: "http://staging.customerb"
customer-c-staging:
- name: "/projects/baseconfig/application/customer-c-staging.name"
- application_id: "/projects/baseconfig/application/customer-c-staging.id"
- pattern: "http://staging.customerc"
customer-a-production:
- name: "/projects/baseconfig/application/customer-a-prod.name"
- application_id: "/projects/baseconfig/application/customer-a-prod.id"
- pattern: "http://customera"
customer-b-production:
- name: "/projects/baseconfig/application/customer-b-prod.name"
- application_id: "/projects/baseconfig/application/customer-b-prod.id"
- pattern: "http://customerb"
customer-c-production:
- name: "/projects/baseconfig/application/customer-c-prod.name"
- application_id: "/projects/baseconfig/application/customer-c-prod.id"
- pattern: "http://customerc"
{
"applicationIdentifier": "{{ .application_id }}",
"filterConfig": {
"pattern": "{{ .pattern }}",
"applicationMatchType": "BEGINS_WITH",
"applicationMatchTarget": "URL"
}
}
./monaco --environments=environments.yaml
👉 We need to update the customer
auto tag rule to include the application.
Hint: You only need to adjust the auto-tag/customertag.json
file. You probably need to experiment in the UI first :)
Time: 15mins
You should now have code which creates the following components:
Create a management zone for each customer and environment which encompasses all processes, process groups, services and applications.
You should end up with 6 management zones:
Time: 20mins
So far we've only created configuration. What about deletion?
Create a file in the root folder (alongside ./monaco
) called delete.yaml
delete.yaml
has the following syntax:
delete:
- "ConfigurationType/ConfigurationName"
For example to delete an auto-tag
which looks like this:
config:
- customer_tag: "customertag.json"
customer_tag:
- name: "customer"
Your delete.yaml
would look like this:
delete:
- "auto-tag/customer"
Run ./monaco
as normal and it will delete your config:
./monaco --environments=environments.yaml
INFO Dynatrace Monitoring as Code v1.0.1
INFO Executing projects in this order:
INFO 1: projects\baseconfig (15 configs)
INFO Processing environment mac_training_environment...
INFO Processing project projects\baseconfig...
INFO Deployment finished without errors
INFO Deleting 1 configs for environment mac_training_environment...
To prevent configuration deletion, just rename the delete.yaml
to something else.
You now have a very stable base setup for your customer. Moreover your customer can take this configuration as code and apply it from their build pipelines.
You can share this configuration with customers and colleagues so they can easily understand what and how you have built things.
You have built this in a completely future-proof and flexible way that your customer can easily understand and amend to any new requirements.
You have successfully built the following:
If you'd like to extend this demo, there are a number of configurations you could still apply as code. Here are some ideas: