{"id":4040,"date":"2020-02-24T18:00:00","date_gmt":"2020-02-24T17:00:00","guid":{"rendered":"https:\/\/www.unicoda.com\/?p=4040"},"modified":"2020-02-27T16:03:18","modified_gmt":"2020-02-27T15:03:18","slug":"gcp-private-kubernetes-cluster-for-helm-installation-of-elasticsearch","status":"publish","type":"post","link":"https:\/\/www.unicoda.com\/?p=4040","title":{"rendered":"GCP Private Kubernetes cluster for Helm installation of Elasticsearch"},"content":{"rendered":"\n<p>In this article, I will list the steps needed to deploy an Elasticsearch cluster on a private Google Cloud Platform (GCP) Kubernetes cluster using Helm, from creating a docker image with Elasticsearch, to the creation of a private Kubernetes cluster and more.<\/p>\n\n\n\n<p>Let&rsquo;s begin.<\/p>\n\n\n\n<!--more-->\n\n\n\n<h2 class=\"wp-block-heading\">Docker image<\/h2>\n\n\n\n<p>First, we need to create our own docker image for elasticsearch, based on the official image provided by elastico. This step is mandatory, because we do not have any connectivity to the official repository from inside a private GCP cluster.<\/p>\n\n\n\n<p>So, on my computer, I&rsquo;m creating a Dockerfile with the following content:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">FROM docker.elastic.co\/elasticsearch\/elasticsearch:7.5.0<\/pre>\n\n\n\n<p>Next step is to build the image and tag (replace PROJECT_ID).<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">docker build --tag elasticsearch-gcs:7.5.0 .\ndocker tag elasticsearch-gcs:7.5.0 gcr.io\/PROJECT_ID\/elasticsearch-gcs:7.5.0<\/pre>\n\n\n\n<p>Then, I push the newly created image to internal gcp repository of my project.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">docker push gcr.io\/PROJECT_ID\/elasticsearch-gcs:7.5.0<\/pre>\n\n\n\n<p>If needed, I authenticate to be able to push the image:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">gcloud auth configure-docker<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">VPC network and client VM<\/h2>\n\n\n\n<p>We will create a dedicated VPC network for the cluster.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">gcloud compute networks create elasticsearch-network --subnet-mode=custom<\/pre>\n\n\n\n<p>Create a subnet in our VPC network.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">gcloud compute networks subnets create elasticsearch-subnet \\\n    --network=elasticsearch-network --range=10.50.0.0\/16<\/pre>\n\n\n\n<p>Create VM which will be used to run kubectl commands.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">gcloud compute instances create --subnet=elasticsearch-subnet \\\n    --scopes cloud-platform es-cluster-proxy<\/pre>\n\n\n\n<p>Make note of the IP of the VM, or get it:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">export CLIENT_IP=`gcloud compute instances describe es-cluster-proxy \\<br>    --format=\"value(networkInterfaces[0].networkIP)\"`<\/pre>\n\n\n\n<p>Create a firewall rule to allow SSH access to the VPC network.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">gcloud compute firewall-rules create elasticsearch-proxy-ssh --network elasticsearch-network  \\\n    --allow tcp:22<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Connectivity<\/h2>\n\n\n\n<h4 class=\"wp-block-heading\">Serverless VPC access<\/h4>\n\n\n\n<p>Create a serverless VPC access for cloud functions. Do not forget to change the region parameter (ex: europe-west2).<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">gcloud compute networks vpc-access connectors create elasticsearch-cluster \\\n--network elasticsearch-network \\\n--region REGION \\\n--range 10.9.8.0\/28<\/pre>\n\n\n\n<p>Don&rsquo;t forget to update all cloud functions to use the newly created VPC connector using:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">--vpc-connector projects\/PROJECT_ID\/locations\/REGION\/connectors\/elasticsearch-cluster<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">VPC network peering<\/h4>\n\n\n\n<p>In order for our backend API to be able to make request to the cluster, we need to peer networks together, that is default network with our newly created network elasticsearch-network.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">gcloud compute networks peerings create elasticsearch-default-peer \\\n    --network=default \\\n    --peer-project PROJECT_ID \\\n    --peer-network elasticsearch-network \\\n    --auto-create-routes<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Private cluster<\/h2>\n\n\n\n<h4 class=\"wp-block-heading\">Creation<\/h4>\n\n\n\n<p>Let&rsquo;s continue by creating a private cluster with no public IP on compute engines used by the cluster. Do not forget to change the zone parameter (ex: europe-west2-a) and to configure the cluster so that it fits your needs.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">gcloud container clusters create \"elasticsearch-cluster\" \\\n  --zone \"ZONE\" \\\n  --no-enable-basic-auth \\\n  --cluster-version \"1.14.10-gke.21\" \\\n  --machine-type \"n1-standard-1\" \\\n  --image-type=\"cos_containerd\" \\\n  --disk-type \"pd-standard\" \\\n  --disk-size \"50\" \\\n  --metadata disable-legacy-endpoints=true \\\n  --scopes \"https:\/\/www.googleapis.com\/auth\/devstorage.read_only\",\"https:\/\/www.googleapis.com\/auth\/logging.write\",\"https:\/\/www.googleapis.com\/auth\/monitoring\",\"https:\/\/www.googleapis.com\/auth\/servicecontrol\",\"https:\/\/www.googleapis.com\/auth\/service.management.readonly\",\"https:\/\/www.googleapis.com\/auth\/trace.append\" \\\n  --num-nodes \"3\" \\\n  --enable-stackdriver-kubernetes \\\n  --enable-ip-alias \\\n  --enable-private-nodes \\\n  --enable-private-endpoint \\\n  --master-ipv4-cidr 172.16.0.32\/28 \\\n  --network elasticsearch-network \\\n  --subnetwork=elasticsearch-subnet \\\n  --no-issue-client-certificate \\\n  --addons HorizontalPodAutoscaling,HttpLoadBalancing \\\n  --enable-autoupgrade \\\n  --enable-autorepair \\\n  # --enable-master-authorized-networks \\\n  # --master-authorized-networks &lt;IP&gt;\/32<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Allow access to VM<\/h4>\n\n\n\n<p>We update our cluster to authorize access from our previously created VM.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">gcloud container clusters update elasticsearch-cluster \\\n    --enable-master-authorized-networks \\\n    --master-authorized-networks &lt;VM_IP&gt;\/32<\/pre>\n\n\n\n<p>Note that this can also be done at cluster creation.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Elasticsearch cluster<\/h2>\n\n\n\n<h4 class=\"wp-block-heading\">Connect to VM<\/h4>\n\n\n\n<p>Connect to proxy VM either with GCP interface in browser, or using gcloud.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">gcloud compute ssh es-cluster-proxy<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Install tools<\/h4>\n\n\n\n<p>Install <code>kubectl<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">sudo apt-get install kubectl<\/pre>\n\n\n\n<p>Install <a rel=\"noreferrer noopener\" aria-label=\"helm (s\u2019ouvre dans un nouvel onglet)\" href=\"https:\/\/helm.sh\/docs\/intro\/install\/\" target=\"_blank\">helm<\/a>.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ curl https:\/\/raw.githubusercontent.com\/helm\/helm\/master\/scripts\/get-helm-3 &gt; get_helm.sh\n$ chmod 700 get_helm.sh\n$ .\/get_helm.sh\n$ helm init<\/pre>\n\n\n\n<p>Add elastic helm charts repo.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">helm repo add elastic https:\/\/helm.elastic.co<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Connect to cluster<\/h4>\n\n\n\n<p>Get cluster credentials.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">gcloud container clusters get-credentials elasticsearch-cluster \\\n--zone ZONE --internal-ip<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Prepare configuration<\/h4>\n\n\n\n<p>Create a YAML file to personalize elasticsearch installation (Change PROJECT_ID).<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">---\nservice:\n  type: LoadBalancer\n  annotations:\n    cloud.google.com\/load-balancer-type: Internal\nreplicas: 2\n\nimage: \"gcr.io\/PROJECT_ID\/elasticsearch-gcs\"\nimageTag: \"7.5.0\"\nresources:\n  requests:\n    cpu: \"100m\"<\/pre>\n\n\n\n<p>Here, we add an annotation so that an internal load balancer will be deployed to expose our cluster on the internal network. We also specify the image to be used, that is our internal image.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Install elasticsearch<\/h4>\n\n\n\n<p>Install elasticsearch with helm.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">helm install --values .\/es-config.yml elasticsearch elastic\/elasticsearch<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Check<\/h4>\n\n\n\n<p>In order to assess deployment, make a request to the IP of the internal load balancer.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ curl http:\/\/10.50.0.xxx:9200\n$ curl http:\/\/10.50.0.xxx:9200\/_cluster\/state?pretty<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Uninstall<\/h4>\n\n\n\n<p>If for any reason, you need to uninstall elasticsearch from cluster, connect back to the VM and connect <code>kubectl<\/code> to cluster, then :<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">helm uninstall elasticsearch<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Notes<\/h2>\n\n\n\n<pre class=\"wp-block-preformatted\"># Get cluster state.\nkubectl get all\n\n# Get pods\nkubectl get pods\n    \n# Check a pod\nkubectl describe pod &lt;pod-name&gt;\n    \n# List gcp images\ngcloud container images list\n    \n# Configure password\nkubectl create secret generic elastic-credentials  --from-literal=password=test --from-literal=username=elastic\n\n# Delete secrets\nkubectl delete secrets elastic-credentials<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Sources<\/h2>\n\n\n\n<p>This is the result of aggregating multiple sources of documentation &#8211;  listed right below &#8211; it is adviced to go through each link to get a better understanding of the whole process.<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><a href=\"https:\/\/cloud.google.com\/solutions\/creating-kubernetes-engine-private-clusters-with-net-proxies\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\"Creating GKE private clusters with network proxies for master access (s\u2019ouvre dans un nouvel onglet)\">Creating GKE private clusters with network proxies for master access<\/a><\/li><li><a href=\"https:\/\/cloud.google.com\/kubernetes-engine\/docs\/how-to\/private-clusters?#private_master\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\"Creating a private cluster with no client access to the public endpoint (s\u2019ouvre dans un nouvel onglet)\">Creating a private cluster with no client access to the public endpoint<\/a><\/li><li><a href=\"https:\/\/cloud.google.com\/kubernetes-engine\/docs\/how-to\/cluster-access-for-kubectl#internal_ip\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\"Generating a kubeconfig entry using a private cluster's internal IP address (s\u2019ouvre dans un nouvel onglet)\">Generating a kubeconfig entry using a private cluster&rsquo;s internal IP address<\/a><\/li><li><a href=\"https:\/\/www.elastic.co\/guide\/en\/cloud-on-k8s\/current\/k8s-custom-images.html\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\"Creating custom images (s\u2019ouvre dans un nouvel onglet)\">Creating custom images<\/a><\/li><li><a href=\"https:\/\/sematext.com\/blog\/kubernetes-elasticsearch\/\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\"Running and Deploying Elasticsearch on Kubernetes (s\u2019ouvre dans un nouvel onglet)\">Running and Deploying Elasticsearch on Kubernetes<\/a><\/li><li><a href=\"https:\/\/github.com\/elastic\/helm-charts\/tree\/master\/elasticsearch\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\"Elasticsearch Helm Chart (s\u2019ouvre dans un nouvel onglet)\">Elasticsearch Helm Chart<\/a><\/li><\/ul>\n","protected":false},"excerpt":{"rendered":"<p>In this article, I will list the steps needed to deploy an Elasticsearch cluster on a private Google Cloud Platform (GCP) Kubernetes cluster using Helm, from creating a docker image with Elasticsearch, to the creation of a private Kubernetes cluster and more. Let&rsquo;s begin.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[31],"tags":[37,500,499,502,501],"class_list":["post-4040","post","type-post","status-publish","format-standard","hentry","category-installation","tag-elasticsearch","tag-google-cloud-platform","tag-helm","tag-kubernetes","tag-private-cluster"],"_links":{"self":[{"href":"https:\/\/www.unicoda.com\/index.php?rest_route=\/wp\/v2\/posts\/4040","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.unicoda.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.unicoda.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.unicoda.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.unicoda.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=4040"}],"version-history":[{"count":11,"href":"https:\/\/www.unicoda.com\/index.php?rest_route=\/wp\/v2\/posts\/4040\/revisions"}],"predecessor-version":[{"id":4058,"href":"https:\/\/www.unicoda.com\/index.php?rest_route=\/wp\/v2\/posts\/4040\/revisions\/4058"}],"wp:attachment":[{"href":"https:\/\/www.unicoda.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=4040"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.unicoda.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=4040"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.unicoda.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=4040"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}