Skip to content

Commit

Permalink
Add Google native GKE config connector example (pulumi#1064)
Browse files Browse the repository at this point in the history
  • Loading branch information
lblackstone authored Aug 23, 2021
1 parent 3e17b86 commit e8428ae
Show file tree
Hide file tree
Showing 5 changed files with 240 additions and 0 deletions.
3 changes: 3 additions & 0 deletions google-native-ts-gke-config-connector/Pulumi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name: gke-config-connector
runtime: nodejs
description: GKE config-connector example
58 changes: 58 additions & 0 deletions google-native-ts-gke-config-connector/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
[![Deploy](https://get.pulumi.com/new/button.svg)](https://app.pulumi.com/new)

# Google GKE Config Connector

An example of deploying a GKE cluster and Config Connector addon using Google Cloud Native provider and TypeScript.
This example is based on the [upstream installation docs](https://cloud.google.com/config-connector/docs/how-to/install-upgrade-uninstall)

## Prerequisites

0. [Ensure you have the latest Node.js and NPM](https://nodejs.org/en/download/)
1. [Install the Pulumi CLI](https://www.pulumi.com/docs/get-started/install/)
2. [Configure Pulumi to access your Google Cloud account](https://www.pulumi.com/docs/intro/cloud-providers/google/setup/)

## Running the App

1. Restore NPM dependencies:

```
$ npm install
```
2. Create a new stack:
```
$ pulumi stack init google-gke-cc
```
3. Configure your Google Cloud project and region:
```
$ pulumi config set google-native:project <projectname>
$ pulumi config set google-native:region <region>
```
4. Run `pulumi up` to preview and deploy changes:
```
$ pulumi up
Previewing changes:
...
5. Clean up your Google Cloud and Pulumi resources:
```
$ pulumi destroy
...
$ pulumi stack rm
...
```
## Caveats
Currently, the following manual steps are required:
1. The Kubernetes provider doesn't natively support patching unmanaged resources, so the update has to be run in three
parts. First, the Google resources including the GKE cluster and IAM policies are created. Next, the existing
CustomResource is imported into Pulumi state, and finally is modified in a subsequent update. Improvements to this
process are tracked in https://github.com/pulumi/pulumi-kubernetes/issues/264
2. IAM Policy isn't deleted when the stack is destroyed, and requires manual cleanup.
148 changes: 148 additions & 0 deletions google-native-ts-gke-config-connector/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
// Copyright 2016-2021, Pulumi Corporation.

import * as google from "@pulumi/google-native";
import * as k8s from "@pulumi/kubernetes";
import * as pulumi from "@pulumi/pulumi";
import * as random from "@pulumi/random";

const config = new pulumi.Config("google-native");
const project = config.require("project");

// TODO: Determine this dynamically once https://github.com/pulumi/pulumi-google-native/issues/166 is done.
const engineVersion = "1.19.9-gke.1900";

const nodeConfig: google.types.input.container.v1.NodeConfigArgs = {
machineType: "n1-standard-2",
oauthScopes: [
"https://www.googleapis.com/auth/compute",
"https://www.googleapis.com/auth/devstorage.read_only",
"https://www.googleapis.com/auth/logging.write",
"https://www.googleapis.com/auth/monitoring",
],
preemptible: true,
};

// Create a GKE cluster with the config connector addon enabled.
const cluster = new google.container.v1.Cluster("cluster", {
initialClusterVersion: engineVersion,
nodePools: [{
config: nodeConfig,
initialNodeCount: 1,
management: {
autoRepair: false,
},
name: "initial",
}],
addonsConfig: {
configConnectorConfig: {
enabled: true,
},
},
loggingService: "logging.googleapis.com/kubernetes", // stackdriver
workloadIdentityConfig: {
workloadPool: `${project}.svc.id.goog`,
},
});

// Create a kubeconfig to connect to the GKE cluster.
const kubeconfig = pulumi.all([cluster.name, cluster.endpoint, cluster.masterAuth]).apply(
([name, endpoint, auth]) => {
const context = `${project}_${name}`;
return `apiVersion: v1
clusters:
- cluster:
certificate-authority-data: ${auth.clusterCaCertificate}
server: https://${endpoint}
name: ${context}
contexts:
- context:
cluster: ${context}
user: ${context}
name: ${context}
current-context: ${context}
kind: Config
preferences: {}
users:
- name: ${context}
user:
auth-provider:
config:
cmd-args: config config-helper --format=json
cmd-path: gcloud
expiry-key: '{.credential.token_expiry}'
token-key: '{.credential.access_token}'
name: gcp
`;
});

// Create a Provider to use the new kubeconfig.
const k8sProvider = new k8s.Provider("k8s", {kubeconfig});

// Create a random suffix for the ServiceAccount.
const saSuffix = new random.RandomPet("saSuffix", {length: 1}).id;

// Create a ServiceAccount for the config connector.
const serviceAccount = new google.iam.v1.ServiceAccount("gkeConfigConnector", {
accountId: pulumi.interpolate`gke-config-connector-${saSuffix}`,
});

// Add new IAM bindings for the config connector.
// Note: These bindings will not be removed during a destroy operation on this resource, and should be removed manually.
google.cloudresourcemanager.v1.getProjectIamPolicy({
resource: project,
}).then(x => {
return new google.cloudresourcemanager.v1.ProjectIamPolicy("iam", {
bindings: [
...x.bindings,
{
members: [pulumi.interpolate`serviceAccount:${serviceAccount.email}`],
role: "roles/owner",
},
{
members: [pulumi.interpolate`serviceAccount:${project}.svc.id.goog[cnrm-system/cnrm-controller-manager]`],
role: "roles/iam.workloadIdentityUser",
},
],
resource: project,
});
});

// Create the Config Connector namespace.
const ccNamespace = new k8s.core.v1.Namespace("config-connector", {
metadata: {
annotations: {
"cnrm.cloud.google.com/project-id": project,
},
},
});

// TODO: This would be easier with https://github.com/pulumi/pulumi-kubernetes/issues/264.
// In the meantime, we create this resource in two steps:
// 1. Import the existing ConfigConnector resource.
// 2. Update the ConfigConnector resource under Pulumi management.

// Step 1
// Once the GKE cluster has been created, run another update with this block uncommented:
// const configConnector = new k8s.apiextensions.CustomResource("config-connector", {
// apiVersion: "core.cnrm.cloud.google.com/v1beta1",
// kind: "ConfigConnector",
// metadata: {
// // The name is restricted to ensure that there is only one ConfigConnector resource installed in your cluster
// name: "configconnector.core.cnrm.cloud.google.com",
// },
// }, {provider: k8sProvider, import: "configconnector.core.cnrm.cloud.google.com"});

// Step 2
// On subsequent updates, comment out the previous import block and run this one instead.
// const configConnector = new k8s.apiextensions.CustomResource("config-connector", {
// apiVersion: "core.cnrm.cloud.google.com/v1beta1",
// kind: "ConfigConnector",
// metadata: {
// // The name is restricted to ensure that there is only one ConfigConnector resource installed in your cluster
// name: "configconnector.core.cnrm.cloud.google.com",
// },
// spec: {
// mode: "cluster",
// googleServiceAccount: serviceAccount.email,
// },
// }, {provider: k8sProvider});
13 changes: 13 additions & 0 deletions google-native-ts-gke-config-connector/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "gke-cloud-connector-ts",
"version": "0.1.0",
"devDependencies": {
"@types/node": "latest"
},
"dependencies": {
"@pulumi/pulumi": "^3.0.0",
"@pulumi/random": "^4.2.0",
"@pulumi/kubernetes": "^3.6.0",
"@pulumi/google-native": "^0.7.0"
}
}
18 changes: 18 additions & 0 deletions google-native-ts-gke-config-connector/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"compilerOptions": {
"strict": true,
"outDir": "bin",
"target": "es2016",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"experimentalDecorators": true,
"pretty": true,
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"index.ts"
]
}

0 comments on commit e8428ae

Please sign in to comment.