forked from pulumi/examples
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request pulumi#749 from pulumi/gke-sa-example
add a gke + service account example
- Loading branch information
Showing
5 changed files
with
313 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
name: gcp-ts-gke-serviceaccount | ||
description: A Google Kubernetes Engine (GKE) + Service account example | ||
runtime: nodejs | ||
template: | ||
config: | ||
gcp:project: | ||
description: The Google Cloud project to deploy into | ||
gcp:zone: | ||
description: The Google Cloud zone | ||
gcp:credentials: | ||
description: Your GCP Service Account key contents for GKE Administration | ||
secret: true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
[![Deploy](https://get.pulumi.com/new/button.svg)](https://app.pulumi.com/new) | ||
|
||
# Google Kubernetes Engine (GKE) Cluster with Service Account | ||
|
||
This example deploys an Google Cloud Platform (GCP) [Google Kubernetes Engine (GKE)](https://cloud.google.com/kubernetes-engine/) cluster, and deploys an example application that consumes a PubSub topic. The cluster has a secret which contains [Google Cloud Service Account Credentials](https://cloud.google.com/iam/docs/service-accounts) | ||
|
||
## Deploying the App | ||
|
||
To deploy your infrastructure, follow the below steps. | ||
|
||
### Prerequisites | ||
|
||
1. [Install Pulumi](https://www.pulumi.com/docs/get-started/install/) | ||
1. [Install Node.js](https://nodejs.org/en/download/) | ||
1. Install a package manager for Node.js, such as [npm](https://www.npmjs.com/get-npm) or [Yarn](https://yarnpkg.com/en/docs/install). | ||
1. [Install Google Cloud SDK (`gcloud`)](https://cloud.google.com/sdk/docs/downloads-interactive) | ||
1. Configure GCP Auth | ||
|
||
* Login using `gcloud` | ||
|
||
```bash | ||
$ gcloud auth login | ||
$ gcloud config set project <YOUR_GCP_PROJECT_HERE> | ||
$ gcloud auth application-default login | ||
``` | ||
> Note: This auth mechanism is meant for inner loop developer | ||
> workflows. If you want to run this example in an unattended service | ||
> account setting, such as in CI/CD, please [follow instructions to | ||
> configure your service account](https://www.pulumi.com/docs/intro/cloud-providers/gcp/setup/). The | ||
> service account must have the role `Kubernetes Engine Admin` / `container.admin`. | ||
### Steps | ||
|
||
After cloning this repo, from this working directory, run these commands: | ||
|
||
1. Install the required Node.js packages: | ||
|
||
This installs the dependent packages [needed](https://www.pulumi.com/docs/intro/concepts/how-pulumi-works/) for our Pulumi program. | ||
|
||
```bash | ||
$ npm install | ||
``` | ||
|
||
1. Create a new Pulumi stack, which is an isolated deployment target for this example: | ||
|
||
This will initialize the Pulumi program in TypeScript. | ||
|
||
```bash | ||
$ pulumi stack init | ||
``` | ||
|
||
1. Set the required GCP configuration variables: | ||
|
||
This sets configuration options and default values for our cluster. | ||
|
||
```bash | ||
$ pulumi config set gcp:project <YOUR_GCP_PROJECT_HERE> | ||
$ pulumi config set gcp:zone us-west1-a // any valid GCP Zone here | ||
``` | ||
|
||
1. Set some optional configuration variables (note, these values are optional and have defaults set): | ||
|
||
```bash | ||
$ pulumi config set name <NAME> | ||
$ pulumi config set machineType n1-standard-1 | ||
``` | ||
|
||
1. Stand up the GKE cluster: | ||
|
||
To preview and deploy changes, run `pulumi update` and select "yes." | ||
|
||
The `update` sub-command shows a preview of the resources that will be created | ||
and prompts on whether to proceed with the deployment. Note that the stack | ||
itself is counted as a resource, though it does not correspond | ||
to a physical cloud resource. | ||
|
||
You can also run `pulumi up --diff` to see and inspect the diffs of the | ||
overall changes expected to take place. | ||
|
||
Running `pulumi up` will deploy the GKE cluster. Note, provisioning a | ||
new GKE cluster takes between 3-5 minutes. | ||
|
||
```bash | ||
|
||
``` | ||
|
||
1. After 3-5 minutes, your cluster will be ready, and the kubeconfig YAML you'll use to connect to the cluster will | ||
be available as an output. | ||
|
||
1. Access the Kubernetes Cluster using `kubectl` | ||
|
||
To access your new Kubernetes cluster using `kubectl`, we need to setup the | ||
`kubeconfig` file and download `kubectl`. We can leverage the Pulumi | ||
stack output in the CLI, as Pulumi facilitates exporting these objects for us. | ||
|
||
```bash | ||
$ pulumi stack output kubeconfig > kubeconfig | ||
$ export KUBECONFIG=$PWD/kubeconfig | ||
$ kubectl version | ||
$ kubectl cluster-info | ||
$ kubectl get nodes | ||
``` | ||
|
||
1. Verify the pubsub example is working | ||
|
||
The pubsub deployment should be running, you can check it by examining the logs: | ||
|
||
```bash | ||
k logs -n pubsub -l appClass=pubsub | ||
Pulling messages from Pub/Sub subscription... | ||
``` | ||
|
||
1. Once you've finished, tear down your stack's resources by destroying and removing it: | ||
|
||
```bash | ||
$ pulumi destroy --yes | ||
$ pulumi stack rm --yes | ||
``` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
// Copyright 2016-2019, Pulumi Corporation. All rights reserved. | ||
import * as gcp from "@pulumi/gcp"; | ||
import * as k8s from "@pulumi/kubernetes"; | ||
import * as pulumi from "@pulumi/pulumi"; | ||
|
||
const config = new pulumi.Config(); | ||
|
||
const name = config.get("name") || | ||
"gke-serviceaccount-example"; | ||
export const masterVersion = config.get("masterVersion") || | ||
gcp.container.getEngineVersions().then(it => it.latestMasterVersion); | ||
const machineType = "n1-standard-1" || config.get("machineType"); | ||
|
||
// Create a service account | ||
const serviceAccount = new gcp.serviceAccount.Account("serviceAccount", { | ||
accountId: name, | ||
displayName: "A service account for a GKE application", | ||
}); | ||
|
||
const serviceAccountIAM = new gcp.projects.IAMBinding("serviceAccount-pub", { | ||
role: "roles/pubsub.subscriber", | ||
members: [pulumi.interpolate`serviceAccount:${serviceAccount.email}`], | ||
}, {parent: serviceAccount}); | ||
|
||
const serviceAccountKey = new gcp.serviceAccount.Key("serviceAccount-key", { | ||
serviceAccountId: serviceAccount.name, | ||
publicKeyType: "TYPE_X509_PEM_FILE", | ||
}, {parent: serviceAccount, additionalSecretOutputs: ["privateKey"]}); | ||
|
||
// Create a GKE cluster | ||
const cluster = new gcp.container.Cluster(name, { | ||
initialNodeCount: 2, | ||
minMasterVersion: masterVersion, | ||
nodeVersion: masterVersion, | ||
nodeConfig: { | ||
machineType: machineType, | ||
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", | ||
], | ||
}, | ||
}); | ||
|
||
// Export the Cluster name | ||
export const clusterName = cluster.name; | ||
|
||
// Manufacture a GKE-style kubeconfig. Note that this is slightly "different" | ||
// because of the way GKE requires gcloud to be in the picture for cluster | ||
// authentication (rather than using the client cert/key directly). | ||
export const kubeconfig = pulumi.all([cluster.name, cluster.endpoint, cluster.masterAuth]).apply(([name, endpoint, masterAuth]) => { | ||
const context = `${gcp.config.project}_${gcp.config.zone}_${name}`; | ||
return `apiVersion: v1 | ||
clusters: | ||
- cluster: | ||
certificate-authority-data: ${masterAuth.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 Kubernetes provider instance that uses our cluster from above. | ||
const clusterProvider = new k8s.Provider(name, { | ||
kubeconfig: kubeconfig, | ||
}); | ||
|
||
const appLabels = {appClass: "pubsub"}; | ||
|
||
// Create a Kubernetes Namespace | ||
const ns = new k8s.core.v1.Namespace("pubsub-ns", { | ||
metadata: { | ||
name: "pubsub", | ||
labels: appLabels, | ||
}, | ||
}, {provider: clusterProvider}); | ||
|
||
|
||
const gcpCredentials = new k8s.core.v1.Secret("gcp-credentials", { | ||
metadata: { | ||
namespace: ns.metadata.name, | ||
labels: appLabels, | ||
}, | ||
type: "Opaque", | ||
stringData: { | ||
"gcp-credentials.json": serviceAccountKey.privateKey.apply((x) => Buffer.from(x, "base64").toString("utf8")), | ||
}, | ||
}, {provider: clusterProvider, parent: ns}); | ||
|
||
const deployment = new k8s.apps.v1.Deployment("pubsub", | ||
{ | ||
metadata: { | ||
namespace: ns.metadata.name, | ||
labels: appLabels, | ||
}, | ||
spec: { | ||
replicas: 1, | ||
selector: {matchLabels: appLabels}, | ||
template: { | ||
metadata: { | ||
labels: appLabels, | ||
}, | ||
spec: { | ||
volumes: [ | ||
{ | ||
name: "google-cloud-key", | ||
secret: { | ||
secretName: gcpCredentials.metadata.name, | ||
}, | ||
}, | ||
], | ||
containers: [ | ||
{ | ||
name: "pubsub-example", | ||
image: "gcr.io/google-samples/pubsub-sample:v1", | ||
volumeMounts: [ | ||
{ | ||
name: "google-cloud-key", | ||
mountPath: "/var/secrets/google", | ||
}, | ||
], | ||
env: [{ | ||
name: "GOOGLE_APPLICATION_CREDENTIALS", | ||
value: "/var/secrets/google/gcp-credentials.json", | ||
}], | ||
}, | ||
], | ||
}, | ||
}, | ||
}, | ||
}, | ||
{ | ||
provider: clusterProvider, parent: ns, | ||
}, | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"name": "gke.typescript", | ||
"devDependencies": { | ||
"@types/node": "^10.0.0" | ||
}, | ||
"dependencies": { | ||
"@pulumi/gcp": "^3.0.0", | ||
"@pulumi/kubernetes": "^2.4.0", | ||
"@pulumi/pulumi": "^2.0.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" | ||
] | ||
} |