Skip to content

Commit 1072060

Browse files
committed
Update deployment instructions
1 parent 0db7bdc commit 1072060

File tree

8 files changed

+174
-69
lines changed

8 files changed

+174
-69
lines changed

.gcloudignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44
/apps/tanx_web/priv/static/
55
/apps/tanx_web/test/
66
/deps/
7-
/kube/
87
/test/
8+
/tmp/

.toys.rb

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,6 @@ def run
127127
flag :project, "--project=VALUE", "-p VALUE"
128128
flag :tag, "--tag=VALUE", "-t VALUE", default: ::Time.now.strftime("%Y-%m-%d-%H%M%S")
129129
flag :name, "--name=VALUE", "-n VALUE", default: "tanx"
130-
flag :ip_addr, "--ip-addr=VALUE", "--ip=VALUE"
131130
flag :yes, "--yes", "-y"
132131

133132
include :exec, exit_on_nonzero_status: true
@@ -141,22 +140,11 @@ def run
141140
puts("Building image: #{image} ...", :bold, :cyan)
142141
exec(["gcloud", "builds", "submit",
143142
"--project", project,
144-
"--config", "cloudbuild.yaml",
145-
"--substitutions", "_IMAGE=#{image},_BUILD_ID=#{tag}"])
146-
if ip_addr
147-
puts("Creating new deployment...", :bold, :cyan)
148-
exec(["kubectl", "run", name, "--image", image, "--port", "8080"])
149-
puts("Creating service...", :bold, :cyan)
150-
cmd = ["kubectl", "expose", "deployment", name,
151-
"--type", "LoadBalancer",
152-
"--port", "80",
153-
"--target-port", "8080"]
154-
cmd.concat(["--load-balancer-ip", ip_addr]) unless ip_addr == "new"
155-
exec(cmd)
156-
else
157-
puts("Updating deployment...", :bold, :cyan)
158-
exec(["kubectl", "set", "image", "deployment/#{name}", "#{name}=#{image}"])
159-
end
143+
"--config", "deploy/cloudbuild.yml",
144+
"--substitutions", "_BUILD_ID=#{tag}",
145+
"."])
146+
puts("Updating deployment...", :bold, :cyan)
147+
exec(["kubectl", "set", "image", "deployment/#{name}", "#{name}=#{image}"])
160148
puts("Done", :bold, :cyan)
161149
end
162150
end

README.md

Lines changed: 64 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ Google Kubernetes Engine.
3737
1. Set up a project on [Google Cloud Console](http://cloud.google.com/console)
3838
if you don't have one, and enable billing.
3939

40+
Optional: Set the `PROJECT_ID` environment variable in your shell, to the
41+
ID of the project you created. Some commands below will use this variable
42+
substitution. (Or you can just substitue the value yourself.)
43+
4044
2. Install the [Google Cloud SDK](https://cloud.google.com/sdk/) on your
4145
workstation if you don't have it. This includes:
4246

@@ -54,12 +58,13 @@ Google Kubernetes Engine.
5458

5559
3. Configure gcloud for your project.
5660

57-
1. Set the default project:
61+
1. Set the default project. (Substitute your project ID.)
5862

59-
gcloud config set project *<your-project-id>*
63+
gcloud config set project ${PROJECT_ID}
6064

6165
2. Set a default zone (i.e. data center location). I think "us-central1-c"
62-
is a good one.
66+
is generally a good one for much of the US, but you may choose one
67+
closer to your location.
6368

6469
gcloud config set compute/zone us-central1-c
6570

@@ -75,27 +80,30 @@ Google Kubernetes Engine.
7580

7681
### Building
7782

78-
We will use Google's [Container Builder](https://cloud.google.com/container-builder/)
83+
We will use Google's [Cloud Build](https://cloud.google.com/cloud-build/)
7984
service to build the Tanx application in a Docker image. Notice that there is
8085
a Dockerfile provided. It uses Distillery to produce an OTP release, and
8186
installs it in a Docker image based on bitwalker's Alpine-Erlang image. We
82-
will just hand this to Container Builder to build an image and upload it to
87+
will just hand this to Google Cloud Build to build an image and upload it to
8388
your project's container registry.
8489

85-
To perform the first build:
90+
To perform the first build.
8691

87-
gcloud container builds submit --tag=gcr.io/${PROJECT_ID}/tanx:v1 .
92+
gcloud builds submit --config deploy/cloudbuild.yml .
8893

89-
Make sure you substitute your project ID. The period at the end is required; it
90-
is the root directory for the application you are building.
94+
The period at the end is required; it is the root directory for the application
95+
you are building.
9196

92-
This will build your image in the cloud, and upload it to the tag you provided.
97+
This will build your image in the cloud, and upload it to your project's image
98+
registry.
9399

94100
### Local builds (optional)
95101

96-
You may also build an image locally using, for example,
97-
`docker build -t tanx .`. Note that Docker 17.05 or later is required because
98-
the Dockerfile is a multistage script.
102+
You may also build an image locally using, for example:
103+
104+
docker build -f deploy/Dockerfile -t tanx .
105+
106+
Note that Docker 17.05 or later is required.
99107

100108
You may run a local build using:
101109

@@ -106,18 +114,18 @@ container.
106114

107115
### Create a cluster
108116

109-
Now we'll set up container engine to host an online tanx server.
117+
Now we'll set up Google Kubernetes Engine to host an online tanx server.
110118

111119
1. Choose a cluster name. For the rest of these instructions, I'll assume that
112120
name is "tanx-cluster-1".
113121

114122
2. Create the cluster.
115123

116-
gcloud container clusters create tanx-cluster-1 --machine-type=n1-highcpu-2 --num-nodes=1
124+
gcloud container clusters create tanx-cluster-1 --num-nodes=2
117125

118-
You can of course replace the cluster name with a name of your choosing.
119-
You can use a different machine type as well, although for now I recommend
120-
highcpu types since the application seems CPU bound for the moment.
126+
You can of course replace the cluster name with a name of your choosing, as
127+
well as change the number of nodes in the cluster and the machine type.
128+
For now, the defaults will get you started.
121129

122130
3. Configure gcloud to use your cluster as default so you don't have to
123131
specify it every time for the remaining gcloud commands.
@@ -126,59 +134,70 @@ Now we'll set up container engine to host an online tanx server.
126134

127135
Replace the name if you named your cluster differently.
128136

129-
Check the cloud console at http://cloud.google.com/console under container
130-
engine to see that your cluster is running. Note that once the cluster is
131-
running, you will be charged for the VM usage.
137+
4. Check the cloud console at http://console.cloud.google.com/kubernetes to
138+
make sure your cluster is running. Note that once the cluster is running,
139+
you will be charged for the VM usage.
140+
141+
5. The app will need to access the kubernetes API so it can configure the OTP
142+
cluster. To set up that access, first give yourself the ability to edit
143+
your cluster's role bindings.
144+
145+
kubectl create clusterrolebinding my-admin-binding \
146+
--clusterrole cluster-admin \
147+
--user $(gcloud config get-value account)
148+
149+
6. Now give the necessary access to the cluster default service account. The
150+
necessary role and binding objects are provided in a config file:
151+
152+
kubectl create -f deploy/cluster-roles.yml
132153

133154
### Deploy to the cluster
134155

135-
A production deployment comprises two parts: a running phoenix container, and a
136-
front-end load balancer (which doesn't do much load balancing per se, but
137-
provides a public IP address.)
156+
A production deployment comprises two parts: a cluster of running containers
157+
managed by a Kubernetes _deployment_, and a front-end load balancer.
138158

139-
We'll assume that you built the image to `gcr.io/${PROJECT_ID}/tanx:v1` and
140-
you've created the Kubernetes cluster as described above.
159+
We'll assume that you've built the image and created the Kubernetes cluster as
160+
described above.
141161

142-
Next we'll create a deployment
162+
First we'll create the deployment and load balancer:
143163

144-
kubectl run tanx-1 --image=gcr.io/${PROJECT_ID}/tanx:v1 --port 8080
164+
kubectl create -f deploy/tanx-deployment.yml
145165

146-
This will run your image on a Kubernetes pod. You may view the running pods
147-
using:
166+
This will create the Kubernetes resources and start up containers in pods. The
167+
initial deployment, however, just runs nginx in a container (rather than your
168+
app). So next you'll need to set the image:
148169

149-
kubectl get pods
170+
kubectl set image deployment/tanx tanx=gcr.io/${PROJECT_ID}/tanx:latest
150171

151-
Now, we need to "expose" the application using a load balancer.
172+
You may view the running pods using:
152173

153-
kubectl expose deployment tanx-1 --type=LoadBalancer --port 80 --target-port 8080
174+
kubectl get pods
154175

155-
This creates a "service" resource pointing at your running tanx pod. After
156-
creating the service, run
176+
And the load balancer using:
157177

158178
kubectl get service
159179

160-
to view the service. Initially, the "external IP" will be pending while
161-
container engine works to procure an IP address for you. If you rerun the
162-
`kubectl get service` command, eventually the IP address will appear. You can
163-
then point your browser at that URL to view the running application.
180+
Initially, the "external IP" for the service will be pending while Kubernetes
181+
Engine works to procure an IP address for you. If you rerun the `get service`
182+
command, eventually the IP address will appear. You can then point your browser
183+
at that URL to view the running application.
164184

165185
### Updating the app
166186

167187
To update the tanx app to reflect changes you have made, rebuild with a new
168188
version tag. For example, if your original build image was tagged
169189
`gcr.io/${PROJECT_ID}/tanx:v1`, you might do a new build as:
170190

171-
gcloud container builds submit --tag=gcr.io/${PROJECT_ID}/tanx:v2 .
191+
gcloud builds submit --config deploy/cloudbuild.yml \
192+
--substitutions _BUILD_ID=v2 .
172193

173194
Now the new image `gcr.io/${PROJECT_ID}/tanx:v2` will be available in your
174195
project's container registry. You may deploy it by setting the pod's image
175196
to the new image:
176197

177-
kubectl set image deployment/tanx-1 tanx-1=gcr.io/${PROJECT_ID}/tanx:v2
198+
kubectl set image deployment/tanx tanx=gcr.io/${PROJECT_ID}/tanx:v2
178199

179-
This generally performs a "rolling" update for zero downtime deploys. However,
180-
since our service has only one instance, it simply stops and starts that single
181-
instance.
200+
This performs a "rolling" update for zero downtime deploys.
182201

183202
### Cleanup and tearing down a deployment
184203

@@ -187,7 +206,7 @@ following.
187206

188207
1. Delete the service
189208

190-
kubectl delete service tanx-1
209+
kubectl delete service tanx
191210

192211
2. Wait for the load balancer to go away. This may take a few minutes. You
193212
may watch the output of the following command to see when this is complete.

cloudbuild.yaml

Lines changed: 0 additions & 6 deletions
This file was deleted.
File renamed without changes.

deploy/cloudbuild.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
steps:
2+
- name: "gcr.io/cloud-builders/docker"
3+
args: ["build", "-f", "deploy/Dockerfile",
4+
"-t", "gcr.io/$PROJECT_ID/tanx:$_BUILD_ID",
5+
"--build-arg", "build_id=$_BUILD_ID",
6+
"."]
7+
8+
substitutions:
9+
_BUILD_ID: latest
10+
11+
images:
12+
- "gcr.io/$PROJECT_ID/tanx:$_BUILD_ID"
File renamed without changes.

deploy/tanx-deployment.yml

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
apiVersion: apps/v1beta1
2+
kind: Deployment
3+
metadata:
4+
name: tanx
5+
labels:
6+
run: tanx
7+
namespace: default
8+
spec:
9+
progressDeadlineSeconds: 600
10+
replicas: 2
11+
selector:
12+
matchLabels:
13+
run: tanx
14+
strategy:
15+
rollingUpdate:
16+
maxSurge: 1
17+
maxUnavailable: 1
18+
type: RollingUpdate
19+
template:
20+
metadata:
21+
labels:
22+
run: tanx
23+
spec:
24+
containers:
25+
- env:
26+
- name: PORT
27+
value: "8080"
28+
- name: REPLACE_OS_VARS
29+
value: "true"
30+
- name: MY_POD_IP
31+
valueFrom:
32+
fieldRef:
33+
apiVersion: v1
34+
fieldPath: status.podIP
35+
image: nginx:latest
36+
imagePullPolicy: IfNotPresent
37+
lifecycle:
38+
preStop:
39+
httpGet:
40+
path: /k8s/pre-stop
41+
port: 8080
42+
scheme: HTTP
43+
livenessProbe:
44+
failureThreshold: 3
45+
httpGet:
46+
path: /k8s/live
47+
port: 8080
48+
scheme: HTTP
49+
initialDelaySeconds: 30
50+
periodSeconds: 10
51+
successThreshold: 1
52+
timeoutSeconds: 1
53+
name: tanx
54+
ports:
55+
- containerPort: 8080
56+
protocol: TCP
57+
readinessProbe:
58+
failureThreshold: 3
59+
httpGet:
60+
path: /k8s/ready
61+
port: 8080
62+
scheme: HTTP
63+
initialDelaySeconds: 5
64+
periodSeconds: 3
65+
successThreshold: 1
66+
timeoutSeconds: 1
67+
resources: {}
68+
terminationMessagePath: /dev/termination-log
69+
terminationMessagePolicy: File
70+
dnsPolicy: ClusterFirst
71+
restartPolicy: Always
72+
schedulerName: default-scheduler
73+
securityContext: {}
74+
terminationGracePeriodSeconds: 30
75+
---
76+
apiVersion: v1
77+
kind: Service
78+
metadata:
79+
name: tanx
80+
labels:
81+
run: tanx
82+
namespace: default
83+
spec:
84+
externalTrafficPolicy: Cluster
85+
ports:
86+
- port: 80
87+
protocol: TCP
88+
targetPort: 8080
89+
selector:
90+
run: tanx
91+
sessionAffinity: None
92+
type: LoadBalancer

0 commit comments

Comments
 (0)