Skip to content

Commit d14f3c6

Browse files
committed
Change to two-stage builds, and display build ID
1 parent 02c9174 commit d14f3c6

File tree

15 files changed

+153
-158
lines changed

15 files changed

+153
-158
lines changed

.toys.rb

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,27 @@ def run
123123
end
124124
end
125125

126+
tool "predeploy" do
127+
flag :project, "--project=VALUE", "-p VALUE"
128+
flag :name, "--name=VALUE", "-n VALUE", default: "tanx"
129+
flag :yes, "--yes", "-y"
130+
131+
include :exec, exit_on_nonzero_status: true
132+
include :terminal
133+
134+
def run
135+
project = get(:project) || capture(["gcloud", "config", "get-value", "project"]).strip
136+
exit(1) unless yes || confirm("Prebuild tanx dependencies in #{project}? ", default: true)
137+
138+
puts("Building base images...", :bold, :cyan)
139+
exec(["gcloud", "builds", "submit",
140+
"--project", project,
141+
"--config", "deploy/build-base.yml",
142+
"."])
143+
puts("Done", :bold, :cyan)
144+
end
145+
end
146+
126147
tool "deploy" do
127148
flag :project, "--project=VALUE", "-p VALUE"
128149
flag :tag, "--tag=VALUE", "-t VALUE", default: ::Time.now.strftime("%Y-%m-%d-%H%M%S")
@@ -134,13 +155,13 @@ def run
134155

135156
def run
136157
project = get(:project) || capture(["gcloud", "config", "get-value", "project"]).strip
137-
image = "gcr.io/#{project}/#{name}:#{tag}"
138-
exit(1) unless yes || confirm("Build #{image} and deploy to GKE in project #{project}? ", default: true)
158+
exit(1) unless yes || confirm("Deploy build #{tag} in project #{project}? ", default: true)
139159

160+
image = "gcr.io/#{project}/#{name}:#{tag}"
140161
puts("Building image: #{image} ...", :bold, :cyan)
141162
exec(["gcloud", "builds", "submit",
142163
"--project", project,
143-
"--config", "deploy/cloudbuild.yml",
164+
"--config", "deploy/build-tanx.yml",
144165
"--substitutions", "_BUILD_ID=#{tag}",
145166
"."])
146167
puts("Updating deployment...", :bold, :cyan)

README.md

Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -80,31 +80,49 @@ Google Kubernetes Engine.
8080

8181
### Building
8282

83-
We will use Google's [Cloud Build](https://cloud.google.com/cloud-build/)
84-
service to build the Tanx application in a Docker image. Notice that there is
85-
a Dockerfile provided. It uses Distillery to produce an OTP release, and
86-
installs it in a Docker image based on bitwalker's Alpine-Erlang image. We
87-
will just hand this to Google Cloud Build to build an image and upload it to
88-
your project's container registry.
83+
Tanx builds are done in two stages. First, you build base images that include
84+
precompiled dependencies, and build tools such as brunch. This build can take
85+
several minutes to complete. Then, a normal application build uses those base
86+
images and just builds the app itself, which is usually pretty quick.
87+
Generally, you must perform a base build once at the beginning, and then any
88+
time your dependencies change. Otherwise, you can perform normal builds.
8989

90-
To perform the first build.
90+
Tanx uses Google's [Cloud Build](https://cloud.google.com/cloud-build/)
91+
service to build Docker images in the cloud. The builds are based on
92+
bitwalker's Alpine-Erlang image, and use Distillery to produce an OTP release
93+
that can be run by Kubernetes or any other container orchestration system.
9194

92-
gcloud builds submit --config deploy/cloudbuild.yml .
95+
To perform a base build:
96+
97+
gcloud builds submit --config deploy/built-base.yml .
9398

9499
The period at the end is required; it is the root directory for the application
95-
you are building.
100+
you are building. This builds the base images (including precompiling the hex
101+
dependencies and node module tools) and uploads them to your project.
102+
103+
Once that is done, you can perform an application build using the base images:
104+
105+
gcloud builds submit --config deploy/build-tanx.yml .
106+
107+
This builds the application image itself and uploads it to your project. The
108+
image is uploaded as `gcr.io/${PROJECT_ID}/tanx:latest`.
96109

97-
This will build your image in the cloud, and upload it to your project's image
98-
registry.
110+
Thereafter, you can rebuild the application by just performing application
111+
builds. Another base build is required whenever the dependencies change.
99112

100113
### Local builds (optional)
101114

102-
You may also build an image locally using, for example:
115+
You may also build images locally using Docker. To build the base images:
103116

104-
docker build -f deploy/Dockerfile -t tanx .
117+
docker build -f deploy/Dockerfile-builder-base -t tanx-builder-base .
118+
docker build -f deploy/Dockerfile-runtime-base -t tanx-runtime-base .
105119

106120
Note that Docker 17.05 or later is required.
107121

122+
Then, to perform an application build using those base images:
123+
124+
docker build -f deploy/Dockerfile-tanx -t tanx .
125+
108126
You may run a local build using:
109127

110128
docker run --rm -p 8080:8080 tanx
@@ -185,10 +203,10 @@ at that URL to view the running application.
185203
### Updating the app
186204

187205
To update the tanx app to reflect changes you have made, rebuild with a new
188-
version tag. For example, if your original build image was tagged
189-
`gcr.io/${PROJECT_ID}/tanx:v1`, you might do a new build as:
206+
version tag. To supply a version tag, pass a `_BUILD_ID` substitution into the
207+
build command. For example, to tag a build as `v2`, do this:
190208

191-
gcloud builds submit --config deploy/cloudbuild.yml \
209+
gcloud builds submit --config deploy/build-tanx.yml \
192210
--substitutions _BUILD_ID=v2 .
193211

194212
Now the new image `gcr.io/${PROJECT_ID}/tanx:v2` will be available in your
@@ -199,6 +217,15 @@ to the new image:
199217

200218
This performs a "rolling" update for zero downtime deploys.
201219

220+
If you do not provide a `_BUILD_ID`, then the tag will default to `latest`. For
221+
example, in the initial application build we did previously, we did not provide
222+
a `_BUILD_ID`, so that image was tagged as `gcr.io/${PROJECT_ID}/tanx:latest`.
223+
224+
Remember that if dependencies have been updated, you need to perform a base
225+
build first, to prebuild the dependencies and update your base images. Do not
226+
pass a `_BUILD_ID` to the base build. Just perform the base build as described
227+
earlier, then perform an application build setting `_BUILD_ID`.
228+
202229
### Cleanup and tearing down a deployment
203230

204231
To clean up a deployment of tanx and stop incurring hosting costs, do the

apps/tanx_web/assets/css/app.scss

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,6 @@ body {
8686
#client-node-name {
8787
font-weight: bold;
8888
}
89+
#client-build-id {
90+
font-weight: bold;
91+
}

apps/tanx_web/assets/js/lobby.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ class Lobby {
115115
this._lobbyChannel.on("update", update => {
116116
this._updateGameTable(update.g)
117117
$('#client-node-name').text(update.d);
118+
$('#client-build-id').text(update.b);
118119
this._gameInfo = {};
119120
update.g.forEach((game) => {
120121
this._gameInfo[game.i] = game;

apps/tanx_web/lib/tanx_web/channels/lobby_channel.ex

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ defmodule TanxWeb.LobbyChannel do
8888
%{i: meta.id, n: meta.display_name, d: meta.node}
8989
end)
9090

91-
push(socket, "update", %{g: games, d: Node.self()})
91+
build_id = System.get_env("TANX_BUILD_ID") || "local"
92+
node_name = Node.self()
93+
push(socket, "update", %{g: games, d: node_name, b: build_id})
9294
end
9395
end

apps/tanx_web/lib/tanx_web/controllers/page_controller.ex

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ defmodule TanxWeb.PageController do
22
use TanxWeb, :controller
33

44
def index(conn, _params) do
5-
build_id = System.get_env("TANX_BUILD_ID")
6-
build_id = if build_id == nil, do: "local", else: build_id
5+
build_id = System.get_env("TANX_BUILD_ID") || "local"
76

87
conn
98
|> assign(:build_id, build_id)

apps/tanx_web/lib/tanx_web/templates/page/index.html.eex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
<div class="col-12">
5656
<h4>Player Info</h4>
5757
<div>Connected to node: <span id="client-node-name"></span></div>
58+
<div>Running build: <span id="client-build-id"></span></div>
5859
<div class="form-inline">
5960
<span class="mr-2">as</span>
6061
<input type="text" id="tanx-name-field" class="form-control input-sm" size="30" maxlength="30" placeholder="(player name)">

deploy/Dockerfile

Lines changed: 0 additions & 122 deletions
This file was deleted.

deploy/Dockerfile-builder-base

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
FROM elixir:alpine
2+
WORKDIR /opt/base-app
3+
COPY . .
4+
ENV MIX_ENV=prod \
5+
REPLACE_OS_VARS=true \
6+
TERM=xterm
7+
RUN apk update \
8+
&& apk --no-cache --update add build-base nodejs nodejs-npm python2 git \
9+
&& mix local.rebar --force \
10+
&& mix local.hex --force \
11+
&& cd /opt/base-app \
12+
&& mix do deps.get, deps.compile \
13+
&& cd apps/tanx_web/assets/ \
14+
&& npm install

deploy/Dockerfile-runtime-base

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
FROM alpine:latest
2+
RUN apk update \
3+
&& apk --no-cache --update add bash openssl-dev

deploy/Dockerfile-tanx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
FROM tanx-builder-base
2+
WORKDIR /opt/app
3+
COPY . .
4+
RUN mv /opt/base-app/_build _build \
5+
&& mv /opt/base-app/deps deps \
6+
&& mv /opt/base-app/apps/tanx_web/assets/node_modules apps/tanx_web/assets/node_modules \
7+
&& mix compile \
8+
&& cd apps/tanx_web/assets \
9+
&& node_modules/brunch/bin/brunch build -p \
10+
&& cd .. \
11+
&& mix phx.digest
12+
RUN mix release --env=prod --verbose \
13+
&& mv _build/prod/rel/tanx /opt/release \
14+
&& mv /opt/release/bin/tanx /opt/release/bin/start_server
15+
16+
FROM tanx-runtime-base
17+
ARG build_id=local
18+
ENV PORT=8080 \
19+
MIX_ENV=prod \
20+
REPLACE_OS_VARS=true \
21+
TANX_BUILD_ID=${build_id}
22+
WORKDIR /opt/app
23+
COPY --from=0 /opt/release .
24+
EXPOSE ${PORT}
25+
CMD ["/opt/app/bin/start_server", "foreground"]

deploy/build-base.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
steps:
2+
- name: "gcr.io/cloud-builders/docker"
3+
args: ["build", "-f", "deploy/Dockerfile-builder-base",
4+
"-t", "gcr.io/$PROJECT_ID/tanx-builder-base:latest",
5+
"."]
6+
- name: "gcr.io/cloud-builders/docker"
7+
args: ["build", "-f", "deploy/Dockerfile-runtime-base",
8+
"-t", "gcr.io/$PROJECT_ID/tanx-runtime-base:latest",
9+
"."]
10+
11+
images:
12+
- "gcr.io/$PROJECT_ID/tanx-builder-base:latest"
13+
- "gcr.io/$PROJECT_ID/tanx-runtime-base:latest"

deploy/build-tanx.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
steps:
2+
- name: 'gcr.io/cloud-builders/docker'
3+
args: ['pull', 'gcr.io/$PROJECT_ID/tanx-builder-base:latest']
4+
- name: 'gcr.io/cloud-builders/docker'
5+
args: ['tag', 'gcr.io/$PROJECT_ID/tanx-builder-base:latest', 'tanx-builder-base']
6+
- name: 'gcr.io/cloud-builders/docker'
7+
args: ['pull', 'gcr.io/$PROJECT_ID/tanx-runtime-base:latest']
8+
- name: 'gcr.io/cloud-builders/docker'
9+
args: ['tag', 'gcr.io/$PROJECT_ID/tanx-runtime-base:latest', 'tanx-runtime-base']
10+
- name: "gcr.io/cloud-builders/docker"
11+
args: ["build", "-f", "deploy/Dockerfile-tanx",
12+
"-t", "gcr.io/$PROJECT_ID/tanx:$_BUILD_ID",
13+
"--build-arg", "build_id=$_BUILD_ID",
14+
"."]
15+
16+
substitutions:
17+
_BUILD_ID: latest
18+
19+
images:
20+
- "gcr.io/$PROJECT_ID/tanx:$_BUILD_ID"

deploy/cloudbuild.yml

Lines changed: 0 additions & 12 deletions
This file was deleted.

0 commit comments

Comments
 (0)