Skip to content

Previews: Always use CLI installer to install monitoring-satellite, instead of jsonnet #12626

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Sep 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .werft/jobs/build/deploy-to-preview-environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,6 @@ export async function deployToPreviewEnvironment(werft: Werft, jobConfig: JobCon
previewName: previewNameFromBranchName(jobConfig.repository.branch),
stackdriverServiceAccount: STACKDRIVER_SERVICEACCOUNT,
werft: werft,
installationMethod: jobConfig.observability.installationMethod,
});
const sliceID = "observability";
monitoringSatelliteInstaller
Expand Down
5 changes: 0 additions & 5 deletions .werft/jobs/build/job-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,9 @@ export interface Repository {
branch: string;
}

export type ObservabilityInstallationMethod = "jsonnet" | "observability-installer";

export interface Observability {
// The branch of gitpod-io/observability to use
branch: string;
// What tool to use to install monitoring-satellite from gitpod-io/observability
installationMethod: ObservabilityInstallationMethod;
}

export function jobConfig(werft: Werft, context: any): JobConfig {
Expand Down Expand Up @@ -115,7 +111,6 @@ export function jobConfig(werft: Werft, context: any): JobConfig {

const observability: Observability = {
branch: context.Annotations.withObservabilityBranch || "main",
installationMethod: context.Annotations.observabilityInstallationMethod || "jsonnet",
};

const jobConfig = {
Expand Down
141 changes: 5 additions & 136 deletions .werft/observability/monitoring-satellite.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { exec } from "../util/shell";
import { getGlobalWerftInstance, Werft } from "../util/werft";
import { Werft } from "../util/werft";
import * as fs from "fs";
import { ObservabilityInstallationMethod } from "../jobs/build/job-config";

type MonitoringSatelliteInstallerOptions = {
werft: Werft;
Expand All @@ -13,7 +12,6 @@ type MonitoringSatelliteInstallerOptions = {
previewName: string;
previewDomain: string;
stackdriverServiceAccount: any;
installationMethod: ObservabilityInstallationMethod;
};

const sliceName = "observability";
Expand All @@ -28,17 +26,12 @@ export class MonitoringSatelliteInstaller {
const {
werft,
branch,
satelliteNamespace,
stackdriverServiceAccount,
previewDomain,
previewName,
nodeExporterPort,
installationMethod,
} = this.options;

werft.log(
sliceName,
`Cloning observability repository - Branch: ${branch} Installation method: ${installationMethod}`,
`Cloning observability repository - Branch: ${branch}`,
);
exec(
`git clone --branch ${branch} https://roboquat:$(cat /mnt/secrets/monitoring-satellite-preview-token/token)@github.com/gitpod-io/observability.git`,
Expand All @@ -60,7 +53,6 @@ export class MonitoringSatelliteInstaller {
fs.writeFileSync(`${pwd}/observability/jsonnetfile.json`, JSON.stringify(jsonnetFile));
exec(`cd observability && jb update`, { slice: sliceName });

if (installationMethod == "observability-installer") {
// As YAML is indentation sensitive we're using json instead so we don't have to worry about
// getting the indentation right when formatting the code in TypeScript.
const observabilityInstallerRenderCmd = `cd observability && \
Expand Down Expand Up @@ -124,132 +116,9 @@ export class MonitoringSatelliteInstaller {
werft.failSlice(sliceName, err)
return
}
} else {
let jsonnetRenderCmd = `cd observability && jsonnet -c -J vendor -m monitoring-satellite/manifests \
--ext-code config="{
namespace: '${satelliteNamespace}',
clusterName: '${previewName}',
tracing: {
honeycombAPIKey: '${process.env.HONEYCOMB_API_KEY}',
honeycombDataset: 'preview-environments',
},
previewEnvironment: {
domain: '${previewDomain}',
nodeExporterPort: ${nodeExporterPort},
},
stackdriver: {
defaultProject: '${stackdriverServiceAccount.project_id}',
clientEmail: '${stackdriverServiceAccount.client_email}',
privateKey: '${stackdriverServiceAccount.private_key}',
},
prometheus: {
externalLabels: {
environment: 'preview-environments',
},
resources: {
requests: { memory: '200Mi', cpu: '50m' },
},
},
remoteWrite: {
username: '${process.env.PROM_REMOTE_WRITE_USER}',
password: '${process.env.PROM_REMOTE_WRITE_PASSWORD}',
urls: ['https://victoriametrics.gitpod.io/api/v1/write'],
writeRelabelConfigs: [{
sourceLabels: ['__name__', 'job'],
separator: ';',
regex: 'rest_client_requests_total.*|http_prober_.*',
action: 'keep',
}],
},
kubescape: {},
pyrra: {},
probe: {
targets: ['http://google.com'],
},
}" \
monitoring-satellite/manifests/yaml-generator.jsonnet | xargs -I{} sh -c 'cat {} | gojsontoyaml > {}.yaml' -- {} && \
find monitoring-satellite/manifests -type f ! -name '*.yaml' ! -name '*.jsonnet' -delete`;
werft.log(sliceName, "rendering YAML files using jsonnet");
exec(jsonnetRenderCmd, { silent: true });
this.postProcessManifests();

this.ensureCorrectInstallationOrder();
this.deployGitpodServiceMonitors();
await this.waitForReadiness(werft);
}
}

private ensureCorrectInstallationOrder() {
const { werft, kubeconfigPath } = this.options;

werft.log(sliceName, "installing monitoring-satellite");
exec(`cd observability && hack/deploy-satellite.sh --kubeconfig ${kubeconfigPath}`, { slice: sliceName });
}

private async waitForReadiness(werft: Werft) {
const { kubeconfigPath, satelliteNamespace } = this.options;

async function execAndLogOnError(
werft: Werft,
objectType: string,
objectName: string,
preSleep: number = 0,
): Promise<void> {
const rc = exec(
`sleep ${preSleep} && kubectl --kubeconfig ${kubeconfigPath} rollout status -n ${satelliteNamespace} ${objectType} ${objectName}`,
{
slice: sliceName,
dontCheckRc: true,
},
).code;
if (rc != 0) {
werft.log(sliceName, `Observability failed to install for ${objectName} of type ${objectType}`);
const statusDebug = exec(
`kubectl --kubeconfig ${kubeconfigPath} -n ${satelliteNamespace} get ${objectType} ${objectName} -o jsonpath="{.status}"`,
{
slice: sliceName,
},
);
werft.log(sliceName, `Status for ${objectName} of type ${objectType}: ${statusDebug}`);
}
return;
}

const checks: Promise<any>[] = [];
// For some reason prometheus' statefulset always take quite some time to get created
// Therefore we wait a couple of seconds
checks.push(execAndLogOnError(werft, "statefulset", "prometheus-k8s", 30));
checks.push(execAndLogOnError(werft, "deployment", "grafana"));
checks.push(execAndLogOnError(werft, "deployment", "kube-state-metrics"));
checks.push(execAndLogOnError(werft, "deployment", "otel-collector"));
// core-dev is just too unstable for node-exporter
// we don't guarantee that it will run at all
checks.push(execAndLogOnError(werft, "daemonset", "node-exporter"));

await Promise.all(checks);
}

private deployGitpodServiceMonitors() {
const { werft, kubeconfigPath } = this.options;

werft.log(sliceName, "installing gitpod ServiceMonitor resources");
exec(`kubectl --kubeconfig ${kubeconfigPath} apply -f observability/monitoring-satellite/manifests/gitpod/`, {
silent: true,
});
}

private postProcessManifests() {
const werft = getGlobalWerftInstance();

// We're hardcoding nodeports, so we can use them in .werft/vm/manifests.ts
// We'll be able to access Prometheus and Grafana's UI by port-forwarding the harvester proxy into the nodePort
werft.log(sliceName, "Post-processing manifests so it works on Harvester");
exec(`yq w -i observability/monitoring-satellite/manifests/grafana/service.yaml spec.type 'NodePort'`);
exec(`yq w -i observability/monitoring-satellite/manifests/prometheus/service.yaml spec.type 'NodePort'`);

exec(
`yq w -i observability/monitoring-satellite/manifests/prometheus/service.yaml spec.ports[0].nodePort 32001`,
);
exec(`yq w -i observability/monitoring-satellite/manifests/grafana/service.yaml spec.ports[0].nodePort 32000`);
// The grafana YAML files we're importing have nodeSelector tied to a nodepool that don't exist in previews
// We're hot-patching the removal os such nodeSelector to make sure Grafana starts
exec(`kubectl patch deployments.apps -n monitoring-satellite grafana --type=json -p="[{'op': 'remove', 'path': '/spec/template/spec/nodeSelector'}]"`)
}
}