From 14f80ef1805d5cc220e0fb2cfab886870360020d Mon Sep 17 00:00:00 2001 From: Crossplane Date: Tue, 4 Dec 2018 08:13:12 +0000 Subject: [PATCH] docs snapshot for crossplane version `master` --- docs/master/cloud-providers.md | 12 +- .../cloud-providers/aws/aws-provider.md | 113 ++++++++ .../cloud-providers/azure/azure-provider.md | 41 +++ .../cloud-providers/gcp/gcp-provider.md | 76 +++++ docs/master/workloads.md | 8 + docs/master/workloads/aws/wordpress-aws.md | 118 ++++++++ .../master/workloads/azure/wordpress-azure.md | 102 +++++++ docs/master/workloads/gcp/wordpress-gcp.md | 270 ++++++++++++++++++ 8 files changed, 731 insertions(+), 9 deletions(-) create mode 100644 docs/master/cloud-providers/aws/aws-provider.md create mode 100644 docs/master/cloud-providers/azure/azure-provider.md create mode 100644 docs/master/cloud-providers/gcp/gcp-provider.md create mode 100644 docs/master/workloads.md create mode 100644 docs/master/workloads/aws/wordpress-aws.md create mode 100644 docs/master/workloads/azure/wordpress-azure.md create mode 100644 docs/master/workloads/gcp/wordpress-gcp.md diff --git a/docs/master/cloud-providers.md b/docs/master/cloud-providers.md index ba64218f..cf970034 100644 --- a/docs/master/cloud-providers.md +++ b/docs/master/cloud-providers.md @@ -6,12 +6,6 @@ indent: true --- # Adding Your Cloud Providers -* [Google Cloud Platform (GCP)](#google-cloud-platform-gcp) -* [Microsoft Azure](#microsoft-azure) -* [Amazon Web Services (AWS)](#amazon-web-services-aws) - -## Google Cloud Platform (GCP) - -## Microsoft Azure - -## Amazon Web Services (AWS) \ No newline at end of file +* [Google Cloud Platform (GCP)](cloud-providers/gcp/gcp-provider.md) +* [Microsoft Azure](cloud-providers/azure/azure-provider.md) +* [Amazon Web Services (AWS)](cloud-providers/aws/aws-provider.md) diff --git a/docs/master/cloud-providers/aws/aws-provider.md b/docs/master/cloud-providers/aws/aws-provider.md new file mode 100644 index 00000000..dfd89108 --- /dev/null +++ b/docs/master/cloud-providers/aws/aws-provider.md @@ -0,0 +1,113 @@ +## Amazon Web Services (AWS) + +The following instructions will help you configure AWS. + +### AWS Credentials + +AWS Credentials file + +Follow the steps in the [AWS SDK for GO](https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/setting-up.html) to get your access key ID and secret access key +1. Open the IAM console. +1. On the navigation menu, choose Users. +1. Choose your IAM user name (not the check box). +1. Open the Security credentials tab, and then choose Create access key. +1. To see the new access key, choose Show. Your credentials resemble the following: + - Access key ID: AKIAIOSFODNN7EXAMPLE + - Secret access key: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY +1. To download the key pair, choose Download .csv file. Store the keys + +Convert *.csv to `.aws/credentials` format +``` +[default] +aws_access_key_id = AKIAIOSFODNN7EXAMPLE +aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY +``` + +**Note** If you have installed and configured `aws cli` you can find your AWS credentials file in `~/.aws/credentials` + +## Setup AWS provider + +Next, create a `example` namespace: + +```console +kubectl create namespace example +``` + +### Create credentials + +1. Get base64 encoded credentials with cat ~/.aws/credentials|base64|tr -d '\n' +1. Replace BASE64ENCODED_AWS_PROVIDER_CREDS in cluster/examples/workloads/wordpress-aws/provider.yaml with value from previous step. + +## Deploy EKS Cluster + +### Create a named keypair +* If you already have an ec2 keypair you can use your existing key pair https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html +* Replace your keypair name in cluster/examples/workloads/wordpress-aws/provider.yaml in EKS_WORKER_KEY_NAME + +### Create your Amazon EKS Service Role +[Original Source](https://docs.aws.amazon.com/eks/latest/userguide/getting-started.html) + +1. Open the IAM console at https://console.aws.amazon.com/iam/. +1. Choose Roles, then Create role. +1. Choose EKS from the list of services, then Allows Amazon EKS to manage your clusters on your behalf for your use case, then Next: Permissions. +1. Choose Next: Review. +1. For Role name, enter a unique name for your role, such as eksServiceRole, then choose Create role. +1. Replace EKS_ROLE_ARN in cluster/examples/workloads/wordpress-aws/provider.yaml with role arn from previous step. + +### Create your Amazon EKS Cluster VPC +[Original Source](https://docs.aws.amazon.com/eks/latest/userguide/getting-started.html) + +1. Open the AWS CloudFormation console at https://console.aws.amazon.com/cloudformation. +1. From the navigation bar, select a Region that supports Amazon EKS. + ```> Note + Amazon EKS is available in the following Regions at this time: + * US West (Oregon) (us-west-2) + * US East (N. Virginia) (us-east-1) + * EU (Ireland) (eu-west-1) + ``` + +1. Choose Create stack. +1. For Choose a template, select Specify an Amazon S3 template URL. +1. Paste the following URL into the text area and choose Next: + ``` + https://amazon-eks.s3-us-west-2.amazonaws.com/cloudformation/2018-11-07/amazon-eks-vpc-sample.yaml + ``` +1. On the Specify Details page, fill out the parameters accordingly, and then choose Next. + ``` + * Stack name: Choose a stack name for your AWS CloudFormation stack. For example, you can call it eks-vpc. + * VpcBlock: Choose a CIDR range for your VPC. You may leave the default value. + * Subnet01Block: Choose a CIDR range for subnet 1. You may leave the default value. + * Subnet02Block: Choose a CIDR range for subnet 2. You may leave the default value. + * Subnet03Block: Choose a CIDR range for subnet 3. You may leave the default value. + ``` +1. (Optional) On the Options page, tag your stack resources. Choose Next. +1. On the Review page, choose Create. +1. When your stack is created, select it in the console and choose Outputs. +1. Replace `EKS_VPC`, `EKS_ROLE_ARN`, `EKS_SUBNETS`, `EKS_SECURITY_GROUP` in cluster/examples/workloads/wordpress-aws/provider.yaml with values from previous step (vpcId, subnetIds, securityGroupIds). Note `EKS_SECURITY_GROUP` needs to be replaced twice in file. +1. Replace `REGION` in cluster/examples/workloads/wordpress-aws/provider.yaml with the region you selected in VPC creation. + +### Create an RDS subnet group +1. Navigate to aws console in same region as eks clsuter +1. Navigate to `RDS` service +1. Naviate to `Subnet groups` in left hand pane +1. Click `Create DB Subnet Group` +1. Name your subnet i.e. eks-db-subnets +1. Select the VPC created in the EKS VPC step +1. Click `Add all subnets related to this VPC` +1. Click Create +1. Replace `RDS_SUBNET_GROUP` in cluster/examples/workloads/wordpress-aws/provider.yaml in DBSubnetgroup name you just created. + +### Create an RDS Security Group (example only) + +**Note**: This will make your RDS instance visible from Anywhere on the internet. This if for **EXAMPLE PURPOSES ONLY**, and +is **NOT RECOMMENDED** for production system. + +1. Navigate to ec2 in the region of the EKS cluster +1. Navigate to security groups +1. Select the same VPC from the EKS cluster. +1. On the Inbound Rules tab, choose Edit. + - For Type, choose `MYSQL/Aurora` + - For Port Range, type `3306` + - For Source, choose `Anywhere` from drop down or type: `0.0.0.0/0` +1. Choose Add another rule if you need to add more IP addresses or different port ranges. +1. Replace `RDS_SECURITY_GROUP` in cluster/examples/workloads/wordpress-aws/provider.yaml with the security group we just created. \ No newline at end of file diff --git a/docs/master/cloud-providers/azure/azure-provider.md b/docs/master/cloud-providers/azure/azure-provider.md new file mode 100644 index 00000000..6df6c8c6 --- /dev/null +++ b/docs/master/cloud-providers/azure/azure-provider.md @@ -0,0 +1,41 @@ +## Microsoft Azure + +Azure service principal credentials are needed for an admin account, which must be created before starting this Wordpress Workload example. + +### Preparing your Microsoft Azure Account + +In order to manage resources in Azure, you must provide credentials for a Azure service principal that Crossplane can use to authenticate. +This assumes that you have already [set up the Azure CLI client](https://docs.microsoft.com/en-us/cli/azure/authenticate-azure-cli?view=azure-cli-latest) with your credentials. + +Create a JSON file that contains all the information needed to connect and authenticate to Azure: + +```console +# create service principal with Owner role +az ad sp create-for-rbac --sdk-auth --role Owner > crossplane-azure-provider-key.json +``` + +Save the `clientID` value from the JSON file we just created to an environment variable: + +```console +export AZURE_CLIENT_ID= +``` + +Now add the required permissions to the service principal we created that allow us to manage the necessary resources in Azure: + +```console +# add required Azure Active Directory permissions +az ad app permission add --id ${AZURE_CLIENT_ID} --api 00000002-0000-0000-c000-000000000000 --api-permissions 1cda74f2-2616-4834-b122-5cb1b07f8a59=Role 78c8a3c8-a07e-4b9e-af1b-b5ccab50a175=Role + +# grant (activate) the permissions +az ad app permission grant --id ${AZURE_CLIENT_ID} --api 00000002-0000-0000-c000-000000000000 --expires never +``` + +You might see an error similar to the following, but that is OK, the permissions should have gone through still: + +```console +Operation failed with status: 'Conflict'. Details: 409 Client Error: Conflict for url: https://graph.windows.net/e7985bc4-a3b3-4f37-b9d2-fa256023b1ae/oauth2PermissionGrants?api-version=1.6 +``` + +After these steps are completed, you should have the following file on your local filesystem: + +* `crossplane-azure-provider-key.json` \ No newline at end of file diff --git a/docs/master/cloud-providers/gcp/gcp-provider.md b/docs/master/cloud-providers/gcp/gcp-provider.md new file mode 100644 index 00000000..aec3339f --- /dev/null +++ b/docs/master/cloud-providers/gcp/gcp-provider.md @@ -0,0 +1,76 @@ +## Google Cloud Platform (GCP) + +Create a GCP example project which we will use to host our example GKE cluster, as well as our example CloudSQL instance. + +- Login into [GCP Console](https://console.cloud.google.com) +- Create a new project (either stand alone or under existing organization) +- Create Example Service Account + - Navigate to: [Create Service Account](https://console.cloud.google.com/iam-admin/serviceaccounts) + - `Service Account Name`: type "example" + - `Service Account ID`: leave auto assigned + - `Service Account Description`: type "Crossplane example" + - Hit `Create` button + - This should advance to the next section `2 Grant this service account to project (optional)` + - We will assign this account 3 roles: + - `Service Account User` + - `Cloud SQL Admin` + - `Kubernetes Engine Admin` + - Hit `Create` button + - This should advance to the next section `3 Grant users access to this service account (optinoal)` + - We don't need to assign any user or admin roles to this account for the example purposes, so you can leave following two fields blank: + - `Service account users role` + - `Service account admins role` + - Next, we will create and export service account key + - Hit `+ Create Key` button. + - This should open a `Create Key` side panel + - Select `json` for the Key type (should be selected by default) + - Hit `Create` + - This should show `Private key saved to your computer` confirmation dialog + - You also should see `crossplane-example-1234-[suffix].json` file in your browser's Download directory + - Save (copy or move) this file into example (this) directory, with new name `key.json` +- Enable `Cloud SQL API` + - Navigate to [Cloud SQL Admin API](https://console.developers.google.com/apis/api/sqladmin.googleapis.com/overview) + - Hit `Enable` +- Enable `Kubernetes Engine API` + - Navigate to [Kubernetes Engine API](https://console.developers.google.com/apis/api/container.googleapis.com/overview) + - Hit `Enable` + +If you have `gcloud` utility, you can ran following commands from the example directory + +```bash +# list your organizations (if applicable) +gcloud organizations list + +# create a new project +export EXAMPLE_PROJECT_NAME=crossplane-example-123 +gcloud projects create $EXAMPLE_PROJECT_NAME --enable-cloud-apis [--organization ORANIZATION_ID] + +# record the PROJECT_ID value of the newly created project +export EXAMPLE_PROJECT_ID=$(gcloud projects list --filter NAME=$EXAMPLE_PROJECT_NAME --format="value(PROJECT_ID)") + +# enable Kubernetes API +gcloud --project $EXAMPLE_PROJECT_ID services enable container.googleapis.com +# enable CloudSQL API +gcloud --project $EXAMPLE_PROJECT_ID services enable sqladmin.googleapis.com + +# create service account +gcloud --project $EXAMPLE_PROJECT_ID iam service-accounts create example-123 --display-name "Crossplane Example" +# export service account email +export EXAMPLE_SA="example-123@$EXAMPLE_PROJECT_ID.iam.gserviceaccount.com" + +# create service account key (this will create a `key.json` file in your current working directory) +gcloud --project $EXAMPLE_PROJECT_ID iam service-accounts keys create --iam-account $EXAMPLE_SA key.json + +# assign roles +gcloud projects add-iam-policy-binding $EXAMPLE_PROJECT_ID --member "serviceAccount:$EXAMPLE_SA" --role="roles/iam.serviceAccountUser" +gcloud projects add-iam-policy-binding $EXAMPLE_PROJECT_ID --member "serviceAccount:$EXAMPLE_SA" --role="roles/cloudsql.admin" +gcloud projects add-iam-policy-binding $EXAMPLE_PROJECT_ID --member "serviceAccount:$EXAMPLE_SA" --role="roles/container.admin" +``` + +### Enable Billing +In order to create GKE clusters you must enable Billing. +- Go to [GCP Console](https://console.cloud.google.com) + - Select example project + - Hit "Enable Billing" +- Go to [Kubernetes Clusters](https://console.cloud.google.com/kubernetes/list) + - Hit "Enable Billing" \ No newline at end of file diff --git a/docs/master/workloads.md b/docs/master/workloads.md new file mode 100644 index 00000000..f2f4c903 --- /dev/null +++ b/docs/master/workloads.md @@ -0,0 +1,8 @@ +# WordPress Demo + +Deploy WordPress application as a Workload into a dynamically provisioned Kubernetes clusters on GKE, +and backed by dynamically provisioned MySQL using Crossplane deployed on Minikube cluster + +* [WordPress Workload on Google Cloud Platform (GCP)](workloads/gcp/wordpress-gcp.md) +* [WordPress Workload on Microsoft Azure](workloads/azure/wordpress-azure.md) +* [WordPress Workload on Amazon Web Services](workloads/aws/wordpress-aws.md) \ No newline at end of file diff --git a/docs/master/workloads/aws/wordpress-aws.md b/docs/master/workloads/aws/wordpress-aws.md new file mode 100644 index 00000000..b8a7a156 --- /dev/null +++ b/docs/master/workloads/aws/wordpress-aws.md @@ -0,0 +1,118 @@ +# Wordpress on AWS + +## Deploy Wordpress Resources + +Now deploy all the Wordpress provider and workload resources, including the RDS database, and EKS cluster with the following single commands: + +Create provider +```console +kubectl create -f cluster/examples/workloads/wordpress-aws/provider.yaml +``` + +Create cluster +```console +kubectl create -f cluster/examples/workloads/wordpress-aws/cluster.yaml +``` + + +Note: It will take about 10 minutes for the EKSCluster to become active, with about another 5 for the nodes to be started and join the cluster. + +## Waiting for load balancer and things to be available + +It will take a while (~15 minutes) for the EKS cluster to be deployed and becoming ready. +You can keep an eye on its status with the following command: + +```console +kubectl -n crossplane-system get ekscluster -o custom-columns=NAME:.metadata.name,STATE:.status.state,CLUSTERNAME:.status.clusterName,ENDPOINT:.status.endpoint,LOCATION:.spec.location,CLUSTERCLASS:.spec.classRef.name,RECLAIMPOLICY:.spec.reclaimPolicy +``` + +Once the cluster is done provisioning, you should see output similar to the following (note the `STATE` field is `Succeeded` and the `ENDPOINT` field has a value): + +```console +NAME STATE CLUSTERNAME ENDPOINT LOCATION CLUSTERCLASS RECLAIMPOLICY +eks-8f1f32c7-f6b4-11e8-844c-025000000001 ACTIVE https://B922855C944FC0567E9050FCD75B6AE5.yl4.us-west-2.eks.amazonaws.com standard-cluster Delete +``` + +Now that the target EKS cluster is ready, we can deploy the Workload that contains all the Wordpress resources, including the SQL database, with the following single command: + +```console +kubectl -n demo create -f cluster/examples/workloads/wordpress-${provider}/workload.yaml +``` + +This will also take awhile to complete, since the MySQL database needs to be deployed before the Wordpress pod can consume it. +You can follow along with the MySQL database deployment with the following: + +```console +kubectl -n crossplane-system get rdsinstance -o custom-columns=NAME:.metadata.name,STATUS:.status.state,CLASS:.spec.classRef.name,VERSION:.spec.version +``` + +Once the `STATUS` column is `Ready` like below, then the Wordpress pod should be able to connect to it: + +```console +NAME STATUS CLASS VERSION +mysql-2a0be04f-f748-11e8-844c-025000000001 available standard-mysql +``` + +Now we can watch the Wordpress pod come online and a public IP address will get assigned to it: + +```console +kubectl -n demo get workload -o custom-columns=NAME:.metadata.name,CLUSTER:.spec.targetCluster.name,NAMESPACE:.spec.targetNamespace,DEPLOYMENT:.spec.targetDeployment.metadata.name,SERVICE-EXTERNAL-IP:.status.service.loadBalancer.ingress[0].ip +``` + +When a public IP address has been assigned, you'll see output similar to the following: + +```console +NAME CLUSTER NAMESPACE DEPLOYMENT SERVICE-EXTERNAL-IP +demo demo-cluster demo wordpress 104.43.240.15 +``` + +Once Wordpress is running and has a public IP address through its service, we can get the URL with the following command: + +```console +echo "http://$(kubectl get workload test-workload -o jsonpath='{.status.service.loadBalancer.ingress[0].ip}')" +``` + +Paste that URL into your browser and you should see Wordpress running and ready for you to walk through the setup experience. You may need to wait a few minutes for this to become active in the aws elb. + +## Connect to your EKSCluster (optional) + +Requires: + * awscli + * aws-iam-authenticator + +Please see [Install instructions](https://docs.aws.amazon.com/eks/latest/userguide/getting-started.html) section: `Install and Configure kubectl for Amazon EKS` + +When the EKSCluster is up and running, you can update your kubeconfig with: +```console +aws eks update-kubeconfig --name +``` + +Node pool is created after the master is up, so expect a few more minutes to wait, but eventually you can see that nodes joined with: +```console +kubectl config use-context +kubectl get nodes +``` + + +## Clean-up + +First delete the workload, which will delete Wordpress and the MySQL database: + +```console +kubectl -n demo delete -f cluster/examples/workloads/wordpress-${provider}/workload.yaml +``` + +Then delete the EKS cluster: + +```console +kubectl delete -f cluster/examples/workloads/wordpress-${provider}/cluster.yaml +``` + +Finally, delete the provider credentials: + +```console +kubectl delete -f cluster/examples/workloads/wordpress-${provider}/provider.yaml +``` + +> Note: There may still be an ELB that was not properly cleaned up, and you will need +to go to EC2 > ELBs and delete it manually. diff --git a/docs/master/workloads/azure/wordpress-azure.md b/docs/master/workloads/azure/wordpress-azure.md new file mode 100644 index 00000000..63d2e6b0 --- /dev/null +++ b/docs/master/workloads/azure/wordpress-azure.md @@ -0,0 +1,102 @@ +# WordPress Crossplane Workload on Microsoft Azure + +## Set environment variables + +Set the following environment variables that will be used in this walkthrough: + +``` +export PROVIDER=AZURE +export provider=azure +export CLUSTER_TYPE=aksclusters +export DATABASE_TYPE=mysqlservers +``` + +## Deploy Wordpress Resources + +Create the Azure provider object in your cluster: + +```console +sed "s/BASE64ENCODED_${PROVIDER}_PROVIDER_CREDS/`cat crossplane-${provider}-provider-key.json|base64|tr -d '\n'`/g;" cluster/examples/workloads/wordpress-${provider}/provider.yaml | kubectl create -f - +``` + +Next, create the AKS cluster that will eventually be the target cluster for your Workload deployment: + +```console +kubectl create -f cluster/examples/workloads/wordpress-${provider}/cluster.yaml +``` + +It will take a while (~15 minutes) for the AKS cluster to be deployed and becoming ready. +You can keep an eye on its status with the following command: + +```console +kubectl -n crossplane-system get akscluster -o custom-columns=NAME:.metadata.name,STATE:.status.state,CLUSTERNAME:.status.clusterName,ENDPOINT:.status.endpoint,LOCATION:.spec.location,CLUSTERCLASS:.spec.classRef.name,RECLAIMPOLICY:.spec.reclaimPolicy +``` + +Once the cluster is done provisioning, you should see output similar to the following (note the `STATE` field is `Succeeded` and the `ENDPOINT` field has a value): + +```console +NAME STATE CLUSTERNAME ENDPOINT LOCATION CLUSTERCLASS RECLAIMPOLICY +aks-587762b3-f72b-11e8-bcbe-0800278fedb1 Succeeded aks-587762b3-f72b-11e8-bcbe-080 crossplane-aks-653c32ef.hcp.centralus.azmk8s.io Central US standard-cluster Delete +``` + +Now that the target AKS cluster is ready, we can deploy the Workload that contains all the Wordpress resources, including the SQL database, with the following single command: + +```console +kubectl create -f cluster/examples/workloads/wordpress-${provider}/workload.yaml +``` + +This will also take awhile to complete, since the MySQL database needs to be deployed before the Wordpress pod can consume it. +You can follow along with the MySQL database deployment with the following: + +```console +kubectl -n crossplane-system get mysqlserver -o custom-columns=NAME:.metadata.name,STATUS:.status.state,CLASS:.spec.classRef.name,VERSION:.spec.version +``` + +Once the `STATUS` column is `Ready` like below, then the Wordpress pod should be able to connect to it: + +```console +NAME STATUS CLASS VERSION +mysql-58425bda-f72d-11e8-bcbe-0800278fedb1 Ready standard-mysql 5.7 +``` + +Now we can watch the Wordpress pod come online and a public IP address will get assigned to it: + +```console +kubectl get workload -o custom-columns=NAME:.metadata.name,CLUSTER:.spec.targetCluster.name,NAMESPACE:.spec.targetNamespace,DEPLOYMENT:.spec.targetDeployment.metadata.name,SERVICE-EXTERNAL-IP:.status.service.loadBalancer.ingress[0].ip +``` + +When a public IP address has been assigned, you'll see output similar to the following: + +```console +NAME CLUSTER NAMESPACE DEPLOYMENT SERVICE-EXTERNAL-IP +test-workload demo-cluster demo wordpress 104.43.240.15 +``` + +Once Wordpress is running and has a public IP address through its service, we can get the URL with the following command: + +```console +echo "http://$(kubectl get workload test-workload -o jsonpath='{.status.service.loadBalancer.ingress[0].ip}')" +``` + +Paste that URL into your browser and you should see Wordpress running and ready for you to walk through the setup experience. + +## Clean-up + +First delete the workload, which will delete Wordpress and the MySQL database: + +```console +kubectl delete -f cluster/examples/workloads/wordpress-${provider}/workload.yaml +``` + +Then delete the AKS cluster: + +```console +kubectl delete -f cluster/examples/workloads/wordpress-${provider}/cluster.yaml +``` + +Finally, delete the provider credentials: + +```console +kubectl delete -f cluster/examples/workloads/wordpress-${provider}/provider.yaml +rm -fr crossplane-${provider}-* +``` \ No newline at end of file diff --git a/docs/master/workloads/gcp/wordpress-gcp.md b/docs/master/workloads/gcp/wordpress-gcp.md new file mode 100644 index 00000000..911072c6 --- /dev/null +++ b/docs/master/workloads/gcp/wordpress-gcp.md @@ -0,0 +1,270 @@ +# WordPress Crossplane Workload on GCP + +Deploy WordPress application as a Workload into a dynamically provisioned Kubernetes cluster on GKE, +and backed by dynamically provisioned MySQL (CloudSQL) using Crossplane deployed on Minikube cluster + +## GCP Setup + +For this demo we must have a Google Cloud service account key in `json` format, which +corresponds to an active/valid GCP Service Account and has been granted the following roles: +- `Service Account User`: needed to have access to the service account information +- `Cloud SQL Admin`: needed to access (create/retrieve/connect/delete) CloudSQL instances +- `Kubernetes Engine User`: needed to access (create/connect/delete) GKE instances + +## WordPress Example +In the course of this demonstration we will show how to prepare and provision a sample application: WordPress which +uses MySQL backend database. + +We will use local (`minikube`) Kubernetes cluster to host `Crossplane` (`Crossplane cluster`) + +To demonstrate `Crossplane` concept of `separation of concerns` during this demo we will assume two identities: +1. Administrator (cluster or cloud) - responsible for setting up credentials and defining resource classes +2. Application Owner (developer) - responsible for defining and deploying application and its dependencies + +### As Administrator +you will perform following tasks: + +- Create Cloud provider credentials +- Define Resource classes +- Create a target Kubernetes cluster (using dynamic provisioning with the cluster resource class) + +**Note**: all artifacts created by the administrator are stored/hosted in the `crossplane-system` namespace, which has +a restricted access, i.e. `Application Owner(s)` do not have access to them. + +For the next steps, make sure your `kubectl` context points to the `Crossplane` cluster + +- Export Project ID + + **NOTE** you can skip this step if you generated GCP Service Account using `gcloud` + ```bash + export DEMO_PROJECT_ID=[your-demo-project-id] + ``` + +- Patch and Apply `provider.yaml`: + ```bash + sed "s/BASE64ENCODED_CREDS/`cat key.json|base64 | tr -d '\n'`/g;s/DEMO_PROJECT_ID/$DEMO_PROJECT_ID/g" cluster/examples/workloads/wordpress-gcp/provider.yaml | kubectl create -f - + ``` + + - Verify that GCP Provider is in READY state + ```bash + kubectl -n crossplane-system get providers.gcp.crossplane.io -o custom-columns=NAME:.metadata.name,STATUS:.status.Conditions[0].Type,PROJECT-ID:.spec.projectID + ``` + Your output should look similar to: + ```bash + NAME STATUS PROJECT-ID + gcp-provider Ready [your-project-id] + ``` + + - Verify that Resource Classes have been created + ```bash + kubectl -n crossplane-system get resourceclass -o custom-columns=NAME:metadata.name,PROVISIONER:.provisioner,PROVIDER:.providerRef.name,RECLAIM-POLICY:.reclaimPolicy + ``` + Your output should be: + ```bash + NAME PROVISIONER PROVIDER RECLAIM-POLICY + standard-cluster gkecluster.compute.gcp.crossplane.io/v1alpha1 gcp-provider Delete + standard-mysql cloudsqlinstance.database.gcp.crossplane.io/v1alpha1 gcp-provider Delete + ``` +- Create a target Kubernetes cluster where `Application Owner(s)` will deploy their `WorkLoad(s)` + + As administrator, you will create a Kubernetes cluster leveraging existing Kubernetes cluster `ResourceClass` and + `Crossplane` Kubernetes cluster dynamic provisioning. + ```bash + kubectl apply -f cluster/examples/workloads/wordpress-gcp/kubernetes.yaml + ``` + + - Verify that Kubernetes Cluster resource was created + ```bash + kubectl -n crossplane-system get kubernetescluster -o custom-columns=NAME:.metadata.name,CLUSTERCLASS:.spec.classReference.name,CLUSTERREF:.spec.resourceName.name + ``` + + Your output should look similar to: + ```bash + NAME CLUSTERCLASS CLUSTERREF + demo-gke-cluster standard-cluster gke-67419e79-f5b3-11e8-9cec-9cb6d08bde99 + ``` + + - Verify that Target GKE cluster was successfully created + ```bash + kubectl -n crossplane-system get gkecluster -o custom-columns=NAME:.metadata.name,STATE:.status.state,CLUSTERNAME:.status.clusterName,ENDPOINT:.status.endpoint,LOCATION:.spec.zone,CLUSTERCLASS:.spec.classRef.name,RECLAIMPOLICY:.spec.reclaimPolicy + ``` + + Your output should look similar to: + ```bash + NAME STATE CLUSTERNAME ENDPOINT LOCATION CLUSTERCLASS RECLAIMPOLICY + gke-67419e79-f5b3-11e8-9cec-9cb6d08bde99 RUNNING gke-6742fe8d-f5b3-11e8-9cec-9cb6d08bde99 146.148.93.40 us-central1-a standard-cluster Delete + ``` + +To recap, as administrator user, you have: +- Defined a `Provider` with Google Service Account credentials +- Defined `ResourceClasses` for `KubernetesCluster` and `CloudSQLInstance` +- Provisioned (dynamically) a GKE Cluster using the `ResourceClass` + +### As Application Owner +you will perform following tasks + +- Define Workload in terms of Resources and Payload (Deployment/Service) which will be deployed onto a Target Kubernetes Cluster +- Define dependency resource requirements, in this case `MySQL` database + +#### MySQL +First, let's take a look at the dependency resource +```yaml +## WordPress MySQL Database Instance +apiVersion: storage.crossplane.io/v1alpha1 +kind: MySQLInstance +metadata: + name: demo + namespace: default +spec: + classReference: + name: standard-mysql + namespace: crossplane-system + engineVersion: "5.7" +``` + +This will request to create a `MySQLInstance` version 5.7, which will be fulfilled by the `standard-mysql` ResourceClass. + +Note, the Application Owner is not aware of any further specifics when it comes down to `MySQLInstance` beyond the engine version. + +#### Workload +```yaml +## WordPress Workload +apiVersion: compute.crossplane.io/v1alpha1 +kind: Workload +metadata: + name: demo + namespace: default +spec: + resources: + - name: demo + secretName: demo + targetCluster: + name: demo-gke-cluster + namespace: crossplane-system + targetDeployment: + apiVersion: extensions/v1beta1 + kind: Deployment + metadata: + name: wordpress + labels: + app: wordpress + spec: + selector: + app: wordpress + strategy: + type: Recreate + template: + metadata: + labels: + app: wordpress + spec: + containers: + - name: wordpress + image: wordpress:4.6.1-apache + env: + - name: WORDPRESS_DB_HOST + valueFrom: + secretKeyRef: + name: demo + key: endpoint + - name: WORDPRESS_DB_USER + valueFrom: + secretKeyRef: + name: demo + key: username + - name: WORDPRESS_DB_PASSWORD + valueFrom: + secretKeyRef: + name: demo + key: password + ports: + - containerPort: 80 + name: wordpress + targetNamespace: demo + targetService: + apiVersion: v1 + kind: Service + metadata: + name: wordpress + spec: + ports: + - port: 80 + selector: + app: wordpress + type: LoadBalancer +``` + +The `Workload` definition spawns multiple constructs and kubernetes object. +- Resources: list of the resources required by the payload application. +- TargetCluster: the cluster where the payload application and all its requirements should be deployed. +- TargetNamespace: the namespace on the target cluster +- Workload Payload: + - TargetDeployment + - TargetService + +- Deploy workload + ```bash + kubectl apply -f cluster/examples/workloads/wordpress-gcp/workload.yaml + ``` +- Wait for `MySQLInstance` to be in `Bound` State + + You can check the status via: + ```bash + kubectl get mysqlinstance -o custom-columns=NAME:.metadata.name,VERSION:.spec.engineVersion,STATE:.status.bindingPhase,CLASS:.spec.classReference.name + ``` + Your output should look like: + ```bash + NAME VERSION STATE CLASS + demo 5.7 Bound standard-mysql + ``` + + **Note**: to check on the concrete resource type status as `Administrator` you can run: + ```bash + kubectl -n crossplane-system get cloudsqlinstance -o custom-columns=NAME:.metadata.name,STATUS:.status.state,CLASS:.spec.classRef.name,VERSION:.spec.databaseVersion + ``` + Your output should be similar to: + ```bash + NAME STATUS CLASS VERSION + mysql-2fea0d8e-f5bb-11e8-9cec-9cb6d08bde99 RUNNABLE standard-mysql MYSQL_5_7 + ``` + +- Wait for `Workload` External IP Address + ```bash + kubectl get workload -o custom-columns=NAME:.metadata.name,CLUSTER:.spec.targetCluster.name,NAMESPACE:.spec.targetNamespace,DEPLOYMENT:.spec.targetDeployment.metadata.name,SERVICE-EXTERNAL-IP:.status.service.loadBalancer.ingress[0].ip + ``` + **Note** the `Workload` is defined in Application Owner's (`default`) namespace + + Your output should look similar to: + ```bash + NAME CLUSTER NAMESPACE DEPLOYMENT SERVICE-EXTERNAL-IP + demo demo-gke-cluster demo wordpress 35.193.100.113 + ``` + +- Verify that `WordPress` service is accessible via `SERVICE-EXTERNAL-IP` by: + - Navigate in your browser to `SERVICE-EXTERNAL-IP` + +## Clean Up + +- Remove `Workload` +```bash +kubectl delete -f cluster/examples/workloads/wordpress-gcp/workload.yaml +``` + +- Remove `KubernetesCluster` +```bash +kubectl delete -f cluster/examples/workloads/wordpress-gcp/kubernetes.yaml +``` + +- Remove GCP Provider and ResourceClasses +```bash +kubectl delete -f cluster/examples/workloads/wordpress-gcp/provider.yaml +``` + +- Delete Google Project +```bash +# list all your projects +gcloud projects list + +# delete demo project +gcloud projects delete [demo-project-id +```