├── .gitignore
├── LICENSE
├── README.md
├── app-homepage.png
├── ci
├── k8s.template.yml
├── pipeline.yml
├── vars-cnb-javawar.yml
├── vars-cnb-nodejs.yml
└── vars-cnb-springboot.yml
├── concourse-building.png
├── concourse-dashboard-building.png
├── concourse-dashboard.png
├── concourse-pipeline.png
├── grafana-dashboard-secured.png
├── grafana-dashboard.png
├── grafana-jvm-update.png
├── grafana
└── kpack-dashboard.json
├── k8s
├── cnb-javawar.yml
├── cnb-nodejs.yml
└── cnb-springboot.yml
└── kpack
├── 01-namespace.yml
├── 02-service-account.yml
├── 03-custom-stack.yml
├── 04-custom-java-builder.yml
├── 05-custom-nodejs-builder.yml
├── credentials
├── dockerhub-creds.template.yml
└── github-creds.template.yml
├── images
├── cnb-javawar-image.yml
├── cnb-nodejs-image.yml
└── cnb-springboot-image.yml
├── jvm-update
└── jvm-update.yml
├── latest
├── jvm-latest.yml
└── stack-latest.yml
└── stack-update
└── stack-update.yml
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | k8s.yml
3 | *-creds.yml
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Building container images at scale using kpack
2 |
3 | This project shows how to leverage [kpack](https://github.com/pivotal/kpack),
4 | an open-source project from [Pivotal](https://pivotal.io), to build container
5 | images in Kubernetes at scale.
6 |
7 | Using kpack, you don't need to write a `Dockerfile` anymore for your app:
8 | [Cloud-Native Buildpacks](https://buildpacks.io) will take care of building your app
9 | from source code, adding runtime environments (such as a JVM or a NodeJS engine),
10 | as well as configuring your app to run well in a containerized environment
11 | ([ever heard of `oom` when using Java in a container?](https://success.docker.com/article/java-app-is-killed-by-docker)).
12 |
13 | kpack runs in a Kubernetes environment: you interact with kpack using YAML files,
14 | which will create Kubernetes native objects. When configuring kpack for your app,
15 | you basically only need to define where to get your app (binary form or source code),
16 | container registry credentials (to store the resulting image) and the container image
17 | destination.
18 | [Please see this GitHub repo to learn how to use kpack](https://github.com/alexandreroman/kpack101).
19 |
20 | In this project, we'll use a kpack installation with
21 | [3 Spring Boot apps](https://github.com/alexandreroman/cnb-springboot)
22 | deployed to a Kubernetes cluster.
23 | [A simple Concourse pipeline](https://github.com/alexandreroman/concourse-k8s-deploy-pipeline)
24 | is used to automatically deploy the latest container images to Kubernetes:
25 | you may use any CI/CD tools as a replacement (such as Jenkins, GitLab, Spinnaker, etc.).
26 |
27 |
28 |
29 | For the purpose of the demonstration, these container images are built with
30 | old JVM versions and an old stack (containing middleware libraries
31 | such as OpenSSL or glibc). In a real-world project, container images are expected
32 | to use the latest buildpacks and stacks: when an update is available, kpack
33 | would automatically update container images.
34 |
35 | We'll simulate these buildpack / stack updates by using a custom kpack Java builder.
36 |
37 | ## How to use it?
38 |
39 | ### Deploying kpack
40 |
41 | Make sure
42 | [kpack is deployed to your Kubernetes cluster](https://github.com/pivotal/kpack/blob/master/docs/install.md).
43 |
44 | This repository has been tested with kpack version
45 | [0.0.8](https://github.com/pivotal/kpack/releases/tag/v0.0.8)
46 | and [Paketo](https://paketo.io/) buildpacks.
47 |
48 | You should have no issues deploying kpack to your favorite Kubernetes cluster.
49 |
50 | kpack resources are running in the `kpack` namespace:
51 | ```bash
52 | $ kubectl -n kpack get pods
53 | NAME READY STATUS RESTARTS AGE
54 | kpack-controller-5f66c774d8-sl9md 1/1 Running 0 7d17h
55 | kpack-webhook-847c887dd-xgtp5 1/1 Running 0 7d17h
56 | ```
57 |
58 | You may access kpack logs to see how the controller reacts to events
59 | (buildpack update, source code change, etc.):
60 | ```bash
61 | $ kubectl -n kpack logs -l app=kpack-controller -f
62 | 2020-02-04T10:42:20.384Z INFO controller/controller.go:351 Reconcile succeeded. Time taken: 1.816832832s. {"knative.dev/traceid": "212e8703-d437-4cf0-967e-0b1e1148caef", "knative.dev/key": "default"}
63 | 2020-02-04T10:42:32.179Z DEBUG controller/controller.go:313 Processing from queue kpack-builders/app-bar-source (depth: 0)
64 | 2020-02-04T10:42:32.723Z DEBUG controller/controller.go:267 Adding to queue kpack-builders/app-bar-source (delay: 1m0s, depth: 0)
65 | 2020-02-04T10:42:32.723Z INFO controller/controller.go:351 Reconcile succeeded. Time taken: 543.884902ms. {"knative.dev/traceid": "d34aedc3-56b0-4399-8cf7-457fbec8b9d1", "knative.dev/key": "kpack-builders/app-bar-source"}
66 | 2020-02-04T10:42:36.597Z DEBUG controller/controller.go:313 Processing from queue kpack-builders/app-foo-source (depth: 0)
67 | 2020-02-04T10:42:36.949Z DEBUG controller/controller.go:313 Processing from queue kpack-builders/app-baz-source (depth: 0)
68 | 2020-02-04T10:42:36.969Z DEBUG controller/controller.go:267 Adding to queue kpack-builders/app-foo-source (delay: 1m0s, depth: 0)
69 | 2020-02-04T10:42:36.969Z INFO controller/controller.go:351 Reconcile succeeded. Time taken: 372.030594ms. {"knative.dev/traceid": "46e19fe7-d200-4093-9538-7d90fabea828", "knative.dev/key": "kpack-builders/app-foo-source"}
70 | 2020-02-04T10:42:37.296Z DEBUG controller/controller.go:267 Adding to queue kpack-builders/app-baz-source (delay: 1m0s, depth: 0)
71 | 2020-02-04T10:42:37.296Z INFO controller/controller.go:351 Reconcile succeeded. Time taken: 347.11171ms. {"knative.dev/traceid": "3b7a349e-2eed-4904-8f09-825800be4f90", "knative.dev/key": "kpack-builders/app-baz-source"}
72 | ```
73 |
74 | ### Configuring kpack
75 |
76 | kpack is up and running: let's configure it.
77 |
78 | Create new file `kpack/credentials/dockerhub-creds.yml` from template
79 | `kpack/credentials/dockerhub-creds.template.yml`, and set up your Docker Hub
80 | credentials (you may also use your own container registry):
81 | ```yaml
82 | apiVersion: v1
83 | kind: Secret
84 | metadata:
85 | name: dockerhub-creds
86 | namespace: kpack-builders
87 | annotations:
88 | build.pivotal.io/docker: https://index.docker.io/v1/
89 | type: kubernetes.io/basic-auth
90 | stringData:
91 | username: johndoe
92 | password: changeme
93 | ```
94 |
95 | Same story for GitHub access: kpack will monitor your Git repository, so that
96 | new container images are built when you update your source code.
97 |
98 | Create new file `kpack/credentials/github-creds.yml` from template
99 | `kpack/credentials/github-creds.template.yml` (feel free to use any Git repository):
100 | ```yaml
101 | apiVersion: v1
102 | kind: Secret
103 | metadata:
104 | name: github-creds
105 | namespace: kpack-builders
106 | annotations:
107 | build.pivotal.io/git: https://github.com
108 | type: kubernetes.io/basic-auth
109 | stringData:
110 | username: johndoe
111 | password: changeme
112 | ```
113 |
114 | Please note you may need to use a
115 | [GitHub access token](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line)
116 | if Two-Factor Authentication is enabled for your GitHub account.
117 |
118 | Then you need to edit container image definitions, targeting your container registry
119 | (see files `kpack/images/app-XXX-image.yml`) with the tag property:
120 | ```yaml
121 | apiVersion: build.pivotal.io/v1alpha1
122 | kind: Image
123 | metadata:
124 | name: app-foo
125 | namespace: kpack-builders
126 | spec:
127 | tag: alexandreroman/cnb-springboot-foo
128 | serviceAccount: kpack-service-account
129 | builder:
130 | name: custom-java-builder
131 | kind: CustomBuilder
132 | cacheSize: "2Gi"
133 | source:
134 | git:
135 | url: https://github.com/alexandreroman/cnb-springboot.git
136 | revision: testing
137 | ```
138 |
139 | You're done!
140 |
141 | Please note a custom Java builder is defined in `kpack/custom-java-builder.yml`.
142 | This Java builder is already configured to use old buildpacks / stacks:
143 | later in this page we'll update this builder in place to reference newer
144 | buildpacks / stacks.
145 |
146 | Deploy this configuration to your Kubernetes cluster:
147 | ```bash
148 | $ kubectl apply -f kpack/credentials
149 | $ kubectl apply -f kpack/custom-java-builder.yml
150 | $ kubectl apply -f kpack/images
151 | ```
152 |
153 | Check kpack configuration (the builder state is expected to be `BuilderReady`):
154 | ```bash
155 | $ kubectl -n kpack-builders describe image app-foo
156 | Name: app-foo
157 | Namespace: kpack-builders
158 | Labels:
159 | Annotations: kubectl.kubernetes.io/last-applied-configuration:
160 | {"apiVersion":"build.pivotal.io/v1alpha1","kind":"Image","metadata":{"annotations":{},"name":"app-foo","namespace":"kpack-builders"},"spec...
161 | API Version: build.pivotal.io/v1alpha1
162 | Kind: Image
163 | Metadata:
164 | Creation Timestamp: 2020-02-04T08:07:36Z
165 | Generation: 1
166 | Resource Version: 19276900
167 | Self Link: /apis/build.pivotal.io/v1alpha1/namespaces/kpack-builders/images/app-foo
168 | UID: 677aacb8-4725-11ea-a1b5-42010a000c0a
169 | Spec:
170 | Builder:
171 | Kind: CustomBuilder
172 | Name: custom-java-builder
173 | Cache Size: 2Gi
174 | Failed Build History Limit: 10
175 | Image Tagging Strategy: BuildNumber
176 | Service Account: kpack-service-account
177 | Source:
178 | Git:
179 | Revision: testing
180 | URL: https://github.com/alexandreroman/cnb-springboot.git
181 | Success Build History Limit: 10
182 | Tag: alexandreroman/cnb-springboot-foo
183 | Status:
184 | Build Cache Name: app-foo-cache
185 | Build Counter: 4
186 | Conditions:
187 | Last Transition Time: 2020-02-04T09:13:28Z
188 | Status: True
189 | Type: Ready
190 | Last Transition Time:
191 | Status: True
192 | Type: BuilderReady
193 | Latest Build Ref: app-foo-build-4-j7b92
194 | Latest Image: index.docker.io/alexandreroman/cnb-springboot-foo@sha256:14d03b8dbce97cd94a83e66f7875f04a75f6a3c9cad6ec0187ad51bdbb372457
195 | Latest Stack: org.cloudfoundry.stacks.cflinuxfs3
196 | Observed Generation: 1
197 | Events:
198 | ```
199 |
200 | ### Deploying sample apps
201 |
202 | Edit Kubernetes descriptors in directory `k8s` to use your container registry:
203 | ```yaml
204 | spec:
205 | containers:
206 | - image: alexandreroman/cnb-springboot-foo
207 | name: app
208 | ```
209 |
210 | Deploy the 3 sample apps:
211 | ```bash
212 | $ kubectl apply -f k8s
213 | ```
214 |
215 | Make sure these apps are running
216 | (in 3 namespaces: `app-foo`, `app-bar`, `app-baz`):
217 | ```bash
218 | $ kubectl get pod,svc --all-namespaces -l app=cnb-springboot
219 | NAMESPACE NAME READY STATUS RESTARTS AGE
220 | app-bar pod/app-797997fb6b-zm8r5 1/1 Running 0 4m1s
221 | app-baz pod/app-76b89bc94b-dbxhm 1/1 Running 0 4m1s
222 | app-foo pod/app-5959488d8f-zt6rv 1/1 Running 0 4m1s
223 |
224 | NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
225 | app-bar service/app LoadBalancer 10.100.200.97 34.77.235.10 80:31084/TCP 18h
226 | app-baz service/app LoadBalancer 10.100.200.106 34.77.72.214 80:32176/TCP 18h
227 | app-foo service/app LoadBalancer 10.100.200.119 35.195.215.162 80:31606/TCP 18h
228 | ```
229 |
230 |
231 |
232 | ### Deploying Concourse pipelines
233 |
234 | Let's create deployment pipelines: we want to automatically deploy the latest
235 | container image to our Kubernetes cluster. We expect kpack to build new container images
236 | as we'll simulate buildpack / stack updates.
237 |
238 | Deployment pipelines are implemented with
239 | [Concourse](https://concourse-ci.org).
240 | A simple `kubectl` command is executed to update Kubernetes deployments
241 | with new container image tags. Each pipeline is started when a new container image
242 | appears in the container registry.
243 |
244 | You first need to set configuration properties according to your environment.
245 |
246 | Create new file `ci/k8s.yml` starting from template `ci/k8s.template.yml`:
247 | ```yaml
248 | kubernetes-config: |
249 | >--- PASTE YOUR .kube/config HERE ---<
250 |
251 | # Select a context from the Kubernetes config. Leave empty to use default context.
252 | kubernetes-context:
253 |
254 | # Match this attribute with your cluster version.
255 | kubernetes-version: 1.15
256 |
257 | # Set to true to disable TLS verification when using kubectl commands.
258 | kubernetes-skip-tls-verification: false
259 |
260 | # Set how long to wait for pods to run (seconds), 0 means "don't wait".
261 | kubernetes-wait-until-ready: 180
262 | ```
263 |
264 | You should only need to paste your `.kube/config` file in the configuration properties.
265 |
266 | Make sure you also update the pipeline configuration for each app (`ci/app-XXX.yml`)
267 | to use your container registry:
268 | ```yaml
269 | container-image: alexandreroman/cnb-springboot-foo
270 | ```
271 |
272 | When you're done, deploy 3 pipelines (one for each app) to your Concourse instance:
273 | ```bash
274 | $ fly -t concourse set-pipeline -p app-foo -c ci/pipeline.yml -l ci/k8s.yml -l ci/app-foo.yml
275 | $ fly -t concourse set-pipeline -p app-bar -c ci/pipeline.yml -l ci/k8s.yml -l ci/app-bar.yml
276 | $ fly -t concourse set-pipeline -p app-baz -c ci/pipeline.yml -l ci/k8s.yml -l ci/app-baz.yml
277 | ```
278 |
279 | Don't forget to unpause all pipelines.
280 |
281 | At this point, every time a new container image is deployed to your container registry,
282 | a pipeline will start to update the Kubernetes deployment with zero downtime.
283 |
284 |
285 |
286 | ### Monitoring application state
287 |
288 | Each app instance (pod) exposes metrics, leveraging Spring Boot Actuator and Micrometer.
289 | Metrics are available at `/actuator/metrics`, but you may also use `/actuator/prometheus`
290 | with Prometheus to scrape metrics.
291 |
292 | A custom metric is available in the app under `app_info`: this counter includes the
293 | Java version and the OpenSSL library version used in a container image.
294 | See `MetricsConfig.java` for implementation details.
295 |
296 | You may manually access this metric to see these values:
297 | ```bash
298 | $ http 35.195.215.162/actuator/metrics/app.info
299 | HTTP/1.1 200
300 | Connection: keep-alive
301 | Content-Disposition: inline;filename=f.txt
302 | Content-Type: application/vnd.spring-boot.actuator.v3+json
303 | Date: Tue, 04 Feb 2020 11:27:30 GMT
304 | Keep-Alive: timeout=60
305 | Transfer-Encoding: chunked
306 |
307 | {
308 | "availableTags": [
309 | {
310 | "tag": "java.version",
311 | "values": [
312 | "11.0.5"
313 | ]
314 | },
315 | {
316 | "tag": "openssl.version",
317 | "values": [
318 | "OpenSSL 1.1.1 11 Sep 2018 built on: Thu Jun 20 17:36:28 2019 UTC"
319 | ]
320 | }
321 | ],
322 | "baseUnit": null,
323 | "description": "Get application info",
324 | "measurements": [
325 | {
326 | "statistic": "COUNT",
327 | "value": 1.0
328 | }
329 | ],
330 | "name": "app.info"
331 | }
332 | ```
333 |
334 | You'd better use a visual dashboard, such as Grafana, to monitor application state.
335 | How lucky you are: this project includes such a dashboard!
336 |
337 | You may not have Prometheus / Grafana available in your Kubernetes cluster:
338 | [use this GitHub repository to deploy these components](https://github.com/alexandreroman/k8s-toolbox).
339 |
340 | Once you're ready, create a new dashboard using file `grafana/kpack-dashboard.json`:
341 |
342 |
343 |
344 | Next step: monitor application state while we'll simulate buildpack / stack updates.
345 |
346 | ### Updating JVM for all container images
347 |
348 | Let's assume a new JVM is out: this version includes many bugfixes, which may resolve
349 | security issues. You want all apps running in production to use this JVM version, right?
350 | How could you update all your container images with this JVM, at scale?
351 |
352 | Search no more: we'll let kpack handle this update for us.
353 |
354 | Apps currently use Java `11.0.5`: we want these apps to use Java `11.0.6`.
355 |
356 | Update the kpack Java builder with new buildpacks:
357 | ```bash
358 | $ kubectl apply -f kpack/jvm-update
359 | ```
360 |
361 | If you observe kpack build logs, a new build should start soon
362 | (using `logs` CLI from kpack):
363 | ```bash
364 | $ logs -namespace kpack-builders -image app-foo
365 | [prepare] prepare:fetch.go:66: Successfully cloned "https://github.com/alexandreroman/cnb-springboot.git" @ "8532c6d23ff8a89f1de4854cbe0615de3cc0c415" in path "/workspace"
366 | [detect] org.cloudfoundry.openjdk v1.2.0
367 | [detect] org.cloudfoundry.buildsystem v1.2.0
368 | [detect] org.cloudfoundry.jvmapplication v1.1.0
369 | [detect] org.cloudfoundry.springboot v1.2.0
370 | [analyze] Restoring metadata for "org.cloudfoundry.openjdk:openjdk-jre" from app image
371 | [analyze] Restoring metadata for "org.cloudfoundry.openjdk:2f08c469c9a8adea1b6ee3444ba2a8242a7e99d87976a077faf037a9eb7f884b" from cache
372 | [analyze] Restoring metadata for "org.cloudfoundry.openjdk:6dd0c9c8a740e6c19149e98034fba8e368fd9aa16ab417aa636854d40db1a161" from cache
373 | [analyze] Restoring metadata for "org.cloudfoundry.openjdk:openjdk-jdk" from cache
374 | [analyze] Restoring metadata for "org.cloudfoundry.buildsystem:build-system-cache" from cache
375 | [analyze] Restoring metadata for "org.cloudfoundry.jvmapplication:executable-jar" from app image
376 | [analyze] Restoring metadata for "org.cloudfoundry.springboot:spring-boot" from app image
377 | [restore] Restoring data for "org.cloudfoundry.openjdk:2f08c469c9a8adea1b6ee3444ba2a8242a7e99d87976a077faf037a9eb7f884b" from cache
378 | [restore] Restoring data for "org.cloudfoundry.openjdk:6dd0c9c8a740e6c19149e98034fba8e368fd9aa16ab417aa636854d40db1a161" from cache
379 | [restore] Restoring data for "org.cloudfoundry.openjdk:openjdk-jdk" from cache
380 | [restore] Restoring data for "org.cloudfoundry.buildsystem:build-system-cache" from cache
381 | [restore] Restoring data for "org.cloudfoundry.jvmapplication:executable-jar" from cache
382 | [restore] Restoring data for "org.cloudfoundry.springboot:spring-boot" from cache
383 | [build]
384 | [build] Cloud Foundry OpenJDK Buildpack v1.2.0
385 | [build] OpenJDK JDK 11.0.6: Contributing to layer
386 | [build] Downloading from https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jdk_x64_linux_hotspot_11.0.6_10.tar.gz
387 | [build] Verifying checksum
388 | [build] Expanding to /layers/org.cloudfoundry.openjdk/openjdk-jdk
389 | [build] Writing JAVA_HOME to build
390 | [build] Writing JDK_HOME to build
391 | [build] OpenJDK JRE 11.0.6: Contributing to layer
392 | [build] Downloading from https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.6%2B10/OpenJDK11U-jre_x64_linux_hotspot_11.0.6_10.tar.gz
393 | [build] Verifying checksum
394 | [build] Expanding to /layers/org.cloudfoundry.openjdk/openjdk-jre
395 | [build] Writing JAVA_HOME to shared
396 | [build] Writing MALLOC_ARENA_MAX to shared
397 | [build] Writing .profile.d/active-processor-count
398 | ...
399 | [export] Reusing layer 'launcher'
400 | [export] Adding layer 'org.cloudfoundry.openjdk:class-counter'
401 | [export] Adding layer 'org.cloudfoundry.openjdk:java-security-properties'
402 | [export] Adding layer 'org.cloudfoundry.openjdk:jvmkill'
403 | [export] Adding layer 'org.cloudfoundry.openjdk:link-local-dns'
404 | [export] Adding layer 'org.cloudfoundry.openjdk:memory-calculator'
405 | [export] Adding layer 'org.cloudfoundry.openjdk:openjdk-jre'
406 | [export] Adding layer 'org.cloudfoundry.openjdk:security-provider-configurer'
407 | [export] Reusing layer 'org.cloudfoundry.jvmapplication:executable-jar'
408 | [export] Reusing layer 'org.cloudfoundry.springboot:spring-boot'
409 | [export] Adding 6/6 app layer(s)
410 | [export] Adding layer 'config'
411 | [export] *** Images (sha256:93936ad676a59795cd4ea28d050b98bed9bd4239d968d4cf847c3044c333d8ed):
412 | [export] alexandreroman/cnb-springboot-foo
413 | [export] index.docker.io/alexandreroman/cnb-springboot-foo:b5.20200204.114613
414 | [export] Adding cache layer 'org.cloudfoundry.openjdk:openjdk-jdk'
415 | [export] Adding cache layer 'org.cloudfoundry.buildsystem:build-system-application'
416 | [export] Reusing cache layer 'org.cloudfoundry.buildsystem:build-system-cache'
417 | [export] Reusing cache layer 'org.cloudfoundry.jvmapplication:executable-jar'
418 | [export] Reusing cache layer 'org.cloudfoundry.springboot:spring-boot'
419 | [completion] Build successful
420 | ```
421 |
422 | New container images are built by kpack: you don't need to edit a `Dockerfile`
423 | to use a new JVM. You don't even need to update your source code!
424 |
425 | Look at the deployment pipeline:
426 |
427 |
428 |
429 | As Kubernetes deployments are getting updated with new container images,
430 | new pods are deployed with the new JVM:
431 |
432 |
433 |
434 | [Remember Heartbleed, the OpenSSL vulnerability issue?](https://en.wikipedia.org/wiki/Heartbleed)
435 |
436 | Suddenly, all container images using OpenSSL (that's a lot of container images!) had
437 | to be patched with a new version of this library. Depending on the number of container
438 | images you run, patching everything could take a lot of time.
439 |
440 | Thankfully we now have kpack!
441 | Let's see how to patch our apps with a newer OpenSSL library version.
442 |
443 | Update the Java builder with a new stack
444 | (which contains middleware librairies such as OpenSSL and glibc):
445 | ```bash
446 | $ kubectl apply -f kpack/stack-update
447 | ```
448 |
449 | kpack soon discovers there's a new stack available, and a new build starts
450 | for each container image:
451 | ```bash
452 | $ logs -namespace kpack-builders -image app-foo
453 | [rebase] *** Images (sha256:14041569872bff7a85c1ed39cf6d41e0c5a5c1b8c6665b90cf89980c9ece3ddb):
454 | [rebase] alexandreroman/cnb-springboot-foo
455 | [rebase] index.docker.io/alexandreroman/cnb-springboot-foo:b6.20200204.120052
456 | [rebase]
457 | [rebase] *** Digest: sha256:14041569872bff7a85c1ed39cf6d41e0c5a5c1b8c6665b90cf89980c9ece3ddb
458 | [completion] Build successful
459 | ```
460 |
461 | Please note that patching container images with a new stack is actually very fast.
462 | kpack leverages Cloud-Native Buildpacks to build container images. Container images
463 | built with this technology are optimized with dedicated layers for key components.
464 | Patching a stack only requires an update to a single layer. Moreover, since all
465 | layers are available in container registries, there is no need to build a new
466 | container image: existing container images are remotely "patched", by replacing
467 | the old stack layer by the newer one. This is why you only see a rebase operation
468 | here.
469 |
470 | In the end, all deployment pipelines will start since new container images are
471 | available:
472 |
473 |
474 |
475 | All running pods are now using fully patched container images:
476 |
477 |
478 |
479 | **Building and securing container images at scale is so easy with kpack!**
480 |
481 | ## Contribute
482 |
483 | Contributions are always welcome!
484 |
485 | Feel free to open issues & send PR.
486 |
487 | ## License
488 |
489 | Copyright © 2020 [VMware, Inc. or its affiliates](https://vmware.com).
490 |
491 | This project is licensed under the [Apache Software License version 2.0](https://www.apache.org/licenses/LICENSE-2.0).
492 |
--------------------------------------------------------------------------------
/app-homepage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexandreroman/kpack-at-scale-demo/cae5a839d00df597c5f097b5ea252e01e77c644d/app-homepage.png
--------------------------------------------------------------------------------
/ci/k8s.template.yml:
--------------------------------------------------------------------------------
1 | kubernetes-config: |
2 | >--- PASTE YOUR .kube/config HERE ---<
3 |
4 | # Select a context from the Kubernetes config. Leave empty to use default context.
5 | kubernetes-context:
6 |
7 | # Match this attribute with your cluster version.
8 | kubernetes-version: 1.15
9 |
10 | # Set to true to disable TLS verification when using kubectl commands.
11 | kubernetes-skip-tls-verification: false
12 |
13 | # Set how long to wait for pods to run (seconds), 0 means "don't wait".
14 | kubernetes-wait-until-ready: 180
15 |
--------------------------------------------------------------------------------
/ci/pipeline.yml:
--------------------------------------------------------------------------------
1 | resource_types:
2 | - name: kubernetes
3 | type: docker-image
4 | source:
5 | repository: zlabjp/kubernetes-resource
6 | tag: "{{kubernetes-version}}"
7 |
8 | resources:
9 | - name: kubernetes-cluster
10 | type: kubernetes
11 | icon: kubernetes
12 | source:
13 | insecure_skip_tls_verify: {{kubernetes-skip-tls-verification}}
14 | kubeconfig: {{kubernetes-config}}
15 | context: {{kubernetes-context}}
16 | namespace: {{kubernetes-namespace}}
17 | - name: container-image
18 | type: docker-image
19 | icon: docker
20 | source:
21 | repository: ((container-image))
22 |
23 | jobs:
24 | - name: deploy-latest-container-image
25 | plan:
26 | - get: container-image
27 | trigger: true
28 | params:
29 | skip_download: true
30 | - put: kubernetes-cluster
31 | params:
32 | kubectl: |
33 | set image deployment ((kubernetes-deployment)) ((kubernetes-container))=$(cat container-image/repository)@$(cat container-image/digest)
34 | wait_until_ready: {{kubernetes-wait-until-ready}}
35 |
--------------------------------------------------------------------------------
/ci/vars-cnb-javawar.yml:
--------------------------------------------------------------------------------
1 | container-image: alexandreroman/cnb-javawar-kpack
2 | kubernetes-namespace: cnb-javawar
3 | kubernetes-deployment: app
4 | kubernetes-container: app
5 |
--------------------------------------------------------------------------------
/ci/vars-cnb-nodejs.yml:
--------------------------------------------------------------------------------
1 | container-image: alexandreroman/cnb-nodejs-kpack
2 | kubernetes-namespace: cnb-nodejs
3 | kubernetes-deployment: app
4 | kubernetes-container: app
5 |
--------------------------------------------------------------------------------
/ci/vars-cnb-springboot.yml:
--------------------------------------------------------------------------------
1 | container-image: alexandreroman/cnb-springboot-kpack
2 | kubernetes-namespace: cnb-springboot
3 | kubernetes-deployment: app
4 | kubernetes-container: app
5 |
--------------------------------------------------------------------------------
/concourse-building.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexandreroman/kpack-at-scale-demo/cae5a839d00df597c5f097b5ea252e01e77c644d/concourse-building.png
--------------------------------------------------------------------------------
/concourse-dashboard-building.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexandreroman/kpack-at-scale-demo/cae5a839d00df597c5f097b5ea252e01e77c644d/concourse-dashboard-building.png
--------------------------------------------------------------------------------
/concourse-dashboard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexandreroman/kpack-at-scale-demo/cae5a839d00df597c5f097b5ea252e01e77c644d/concourse-dashboard.png
--------------------------------------------------------------------------------
/concourse-pipeline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexandreroman/kpack-at-scale-demo/cae5a839d00df597c5f097b5ea252e01e77c644d/concourse-pipeline.png
--------------------------------------------------------------------------------
/grafana-dashboard-secured.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexandreroman/kpack-at-scale-demo/cae5a839d00df597c5f097b5ea252e01e77c644d/grafana-dashboard-secured.png
--------------------------------------------------------------------------------
/grafana-dashboard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexandreroman/kpack-at-scale-demo/cae5a839d00df597c5f097b5ea252e01e77c644d/grafana-dashboard.png
--------------------------------------------------------------------------------
/grafana-jvm-update.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexandreroman/kpack-at-scale-demo/cae5a839d00df597c5f097b5ea252e01e77c644d/grafana-jvm-update.png
--------------------------------------------------------------------------------
/grafana/kpack-dashboard.json:
--------------------------------------------------------------------------------
1 | {
2 | "annotations": {
3 | "list": [
4 | {
5 | "builtIn": 1,
6 | "datasource": "-- Grafana --",
7 | "enable": true,
8 | "hide": true,
9 | "iconColor": "rgba(0, 211, 255, 1)",
10 | "name": "Annotations & Alerts",
11 | "type": "dashboard"
12 | }
13 | ]
14 | },
15 | "editable": true,
16 | "gnetId": null,
17 | "graphTooltip": 0,
18 | "id": 1,
19 | "links": [],
20 | "panels": [
21 | {
22 | "cacheTimeout": null,
23 | "colorBackground": false,
24 | "colorValue": false,
25 | "colors": [
26 | "#299c46",
27 | "rgba(237, 129, 40, 0.89)",
28 | "#d44a3a"
29 | ],
30 | "datasource": null,
31 | "format": "none",
32 | "gauge": {
33 | "maxValue": 100,
34 | "minValue": 0,
35 | "show": false,
36 | "thresholdLabels": false,
37 | "thresholdMarkers": true
38 | },
39 | "gridPos": {
40 | "h": 2,
41 | "w": 4,
42 | "x": 0,
43 | "y": 0
44 | },
45 | "id": 10,
46 | "interval": null,
47 | "links": [],
48 | "mappingType": 1,
49 | "mappingTypes": [
50 | {
51 | "name": "value to text",
52 | "value": 1
53 | },
54 | {
55 | "name": "range to text",
56 | "value": 2
57 | }
58 | ],
59 | "maxDataPoints": 100,
60 | "nullPointMode": "connected",
61 | "nullText": null,
62 | "options": {},
63 | "postfix": "",
64 | "postfixFontSize": "50%",
65 | "prefix": "",
66 | "prefixFontSize": "50%",
67 | "rangeMaps": [
68 | {
69 | "from": "null",
70 | "text": "N/A",
71 | "to": "null"
72 | }
73 | ],
74 | "sparkline": {
75 | "fillColor": "rgba(31, 118, 189, 0.18)",
76 | "full": false,
77 | "lineColor": "rgb(31, 120, 193)",
78 | "show": false,
79 | "ymax": null,
80 | "ymin": null
81 | },
82 | "tableColumn": "",
83 | "targets": [
84 | {
85 | "expr": "sum(app_info_total)",
86 | "instant": true,
87 | "refId": "A"
88 | }
89 | ],
90 | "thresholds": "",
91 | "timeFrom": null,
92 | "timeShift": null,
93 | "title": "Pods Running",
94 | "type": "singlestat",
95 | "valueFontSize": "80%",
96 | "valueMaps": [
97 | {
98 | "op": "=",
99 | "text": "N/A",
100 | "value": "null"
101 | }
102 | ],
103 | "valueName": "current"
104 | },
105 | {
106 | "aliasColors": {
107 | "sum(app_info_total{java_version=\"11.0.5\"})": "red"
108 | },
109 | "bars": false,
110 | "dashLength": 10,
111 | "dashes": false,
112 | "datasource": null,
113 | "fill": 1,
114 | "fillGradient": 0,
115 | "gridPos": {
116 | "h": 8,
117 | "w": 9,
118 | "x": 4,
119 | "y": 0
120 | },
121 | "hiddenSeries": false,
122 | "id": 2,
123 | "legend": {
124 | "avg": false,
125 | "current": false,
126 | "max": false,
127 | "min": false,
128 | "show": false,
129 | "total": false,
130 | "values": false
131 | },
132 | "lines": true,
133 | "linewidth": 2,
134 | "nullPointMode": "null as zero",
135 | "options": {
136 | "dataLinks": []
137 | },
138 | "percentage": false,
139 | "pointradius": 2,
140 | "points": false,
141 | "renderer": "flot",
142 | "seriesOverrides": [],
143 | "spaceLength": 10,
144 | "stack": false,
145 | "steppedLine": false,
146 | "targets": [
147 | {
148 | "expr": "sum(app_info_total{java_version=\"11.0.6\"})",
149 | "instant": false,
150 | "refId": "A"
151 | }
152 | ],
153 | "thresholds": [],
154 | "timeFrom": null,
155 | "timeRegions": [],
156 | "timeShift": null,
157 | "title": "Java 11.0.6",
158 | "tooltip": {
159 | "shared": true,
160 | "sort": 0,
161 | "value_type": "individual"
162 | },
163 | "type": "graph",
164 | "xaxis": {
165 | "buckets": null,
166 | "mode": "time",
167 | "name": null,
168 | "show": true,
169 | "values": []
170 | },
171 | "yaxes": [
172 | {
173 | "decimals": 0,
174 | "format": "short",
175 | "label": null,
176 | "logBase": 1,
177 | "max": null,
178 | "min": "0",
179 | "show": true
180 | },
181 | {
182 | "format": "short",
183 | "label": null,
184 | "logBase": 1,
185 | "max": null,
186 | "min": null,
187 | "show": true
188 | }
189 | ],
190 | "yaxis": {
191 | "align": false,
192 | "alignLevel": null
193 | }
194 | },
195 | {
196 | "aliasColors": {
197 | "sum(app_info_total{openssl_version=\"OpenSSL 1.1.1 11 Sep 2018 built on: Thu Jun 20 17:36:28 2019 UTC\"})": "red"
198 | },
199 | "bars": false,
200 | "dashLength": 10,
201 | "dashes": false,
202 | "datasource": null,
203 | "fill": 1,
204 | "fillGradient": 0,
205 | "gridPos": {
206 | "h": 8,
207 | "w": 9,
208 | "x": 13,
209 | "y": 0
210 | },
211 | "hiddenSeries": false,
212 | "id": 6,
213 | "legend": {
214 | "avg": false,
215 | "current": false,
216 | "max": false,
217 | "min": false,
218 | "show": false,
219 | "total": false,
220 | "values": false
221 | },
222 | "lines": true,
223 | "linewidth": 2,
224 | "nullPointMode": "null as zero",
225 | "options": {
226 | "dataLinks": []
227 | },
228 | "percentage": false,
229 | "pointradius": 2,
230 | "points": false,
231 | "renderer": "flot",
232 | "seriesOverrides": [],
233 | "spaceLength": 10,
234 | "stack": false,
235 | "steppedLine": false,
236 | "targets": [
237 | {
238 | "expr": "sum(app_info_total{openssl_version=\"OpenSSL 1.1.1 11 Sep 2018 built on: Thu Jun 20 17:36:28 2019 UTC\"})",
239 | "refId": "A"
240 | }
241 | ],
242 | "thresholds": [],
243 | "timeFrom": null,
244 | "timeRegions": [],
245 | "timeShift": null,
246 | "title": "OpenSSL Jun 2019",
247 | "tooltip": {
248 | "shared": true,
249 | "sort": 0,
250 | "value_type": "individual"
251 | },
252 | "type": "graph",
253 | "xaxis": {
254 | "buckets": null,
255 | "mode": "time",
256 | "name": null,
257 | "show": true,
258 | "values": []
259 | },
260 | "yaxes": [
261 | {
262 | "decimals": 0,
263 | "format": "short",
264 | "label": null,
265 | "logBase": 1,
266 | "max": null,
267 | "min": "0",
268 | "show": true
269 | },
270 | {
271 | "format": "short",
272 | "label": null,
273 | "logBase": 1,
274 | "max": null,
275 | "min": null,
276 | "show": true
277 | }
278 | ],
279 | "yaxis": {
280 | "align": false,
281 | "alignLevel": null
282 | }
283 | },
284 | {
285 | "cacheTimeout": null,
286 | "colorBackground": true,
287 | "colorPrefix": false,
288 | "colorValue": false,
289 | "colors": [
290 | "#C4162A",
291 | "#FA6400",
292 | "#37872D"
293 | ],
294 | "datasource": null,
295 | "format": "none",
296 | "gauge": {
297 | "maxValue": 100,
298 | "minValue": 0,
299 | "show": false,
300 | "thresholdLabels": false,
301 | "thresholdMarkers": true
302 | },
303 | "gridPos": {
304 | "h": 2,
305 | "w": 4,
306 | "x": 0,
307 | "y": 2
308 | },
309 | "id": 14,
310 | "interval": null,
311 | "links": [],
312 | "mappingType": 1,
313 | "mappingTypes": [
314 | {
315 | "name": "value to text",
316 | "value": 1
317 | },
318 | {
319 | "name": "range to text",
320 | "value": 2
321 | }
322 | ],
323 | "maxDataPoints": 100,
324 | "nullPointMode": "connected",
325 | "nullText": null,
326 | "options": {},
327 | "postfix": "",
328 | "postfixFontSize": "50%",
329 | "prefix": "",
330 | "prefixFontSize": "50%",
331 | "rangeMaps": [
332 | {
333 | "from": "null",
334 | "text": "N/A",
335 | "to": "null"
336 | }
337 | ],
338 | "sparkline": {
339 | "fillColor": "rgba(31, 118, 189, 0.18)",
340 | "full": false,
341 | "lineColor": "rgb(31, 120, 193)",
342 | "show": false,
343 | "ymax": null,
344 | "ymin": null
345 | },
346 | "tableColumn": "",
347 | "targets": [
348 | {
349 | "expr": "sum(app_info_total{java_version=\"11.0.7\"})",
350 | "instant": true,
351 | "refId": "A"
352 | }
353 | ],
354 | "thresholds": "1,2",
355 | "timeFrom": null,
356 | "timeShift": null,
357 | "title": "Java Pods Up-to-date",
358 | "type": "singlestat",
359 | "valueFontSize": "80%",
360 | "valueMaps": [
361 | {
362 | "op": "=",
363 | "text": "0",
364 | "value": "null"
365 | }
366 | ],
367 | "valueName": "current"
368 | },
369 | {
370 | "cacheTimeout": null,
371 | "colorBackground": true,
372 | "colorPrefix": false,
373 | "colorValue": false,
374 | "colors": [
375 | "#C4162A",
376 | "#FA6400",
377 | "#37872D"
378 | ],
379 | "datasource": null,
380 | "format": "none",
381 | "gauge": {
382 | "maxValue": 100,
383 | "minValue": 0,
384 | "show": false,
385 | "thresholdLabels": false,
386 | "thresholdMarkers": true
387 | },
388 | "gridPos": {
389 | "h": 2,
390 | "w": 4,
391 | "x": 0,
392 | "y": 4
393 | },
394 | "id": 15,
395 | "interval": null,
396 | "links": [],
397 | "mappingType": 1,
398 | "mappingTypes": [
399 | {
400 | "name": "value to text",
401 | "value": 1
402 | },
403 | {
404 | "name": "range to text",
405 | "value": 2
406 | }
407 | ],
408 | "maxDataPoints": 100,
409 | "nullPointMode": "connected",
410 | "nullText": null,
411 | "options": {},
412 | "postfix": "",
413 | "postfixFontSize": "50%",
414 | "prefix": "",
415 | "prefixFontSize": "50%",
416 | "rangeMaps": [
417 | {
418 | "from": "null",
419 | "text": "N/A",
420 | "to": "null"
421 | }
422 | ],
423 | "sparkline": {
424 | "fillColor": "rgba(31, 118, 189, 0.18)",
425 | "full": false,
426 | "lineColor": "rgb(31, 120, 193)",
427 | "show": false,
428 | "ymax": null,
429 | "ymin": null
430 | },
431 | "tableColumn": "",
432 | "targets": [
433 | {
434 | "expr": "sum(app_info_total{openssl_version=\"OpenSSL 1.1.1 11 Sep 2018 built on: Tue Nov 12 16:58:35 2019 UTC\"})",
435 | "instant": true,
436 | "refId": "A"
437 | }
438 | ],
439 | "thresholds": "1,3",
440 | "timeFrom": null,
441 | "timeShift": null,
442 | "title": "OpenSSL Up-to-date",
443 | "type": "singlestat",
444 | "valueFontSize": "80%",
445 | "valueMaps": [
446 | {
447 | "op": "=",
448 | "text": "0",
449 | "value": "null"
450 | }
451 | ],
452 | "valueName": "current"
453 | },
454 | {
455 | "aliasColors": {},
456 | "bars": false,
457 | "dashLength": 10,
458 | "dashes": false,
459 | "datasource": null,
460 | "fill": 1,
461 | "fillGradient": 0,
462 | "gridPos": {
463 | "h": 8,
464 | "w": 9,
465 | "x": 4,
466 | "y": 8
467 | },
468 | "hiddenSeries": false,
469 | "id": 4,
470 | "legend": {
471 | "avg": false,
472 | "current": false,
473 | "max": false,
474 | "min": false,
475 | "show": false,
476 | "total": false,
477 | "values": false
478 | },
479 | "lines": true,
480 | "linewidth": 2,
481 | "nullPointMode": "null as zero",
482 | "options": {
483 | "dataLinks": []
484 | },
485 | "percentage": false,
486 | "pointradius": 2,
487 | "points": false,
488 | "renderer": "flot",
489 | "seriesOverrides": [],
490 | "spaceLength": 10,
491 | "stack": false,
492 | "steppedLine": false,
493 | "targets": [
494 | {
495 | "expr": "sum(app_info_total{java_version=\"11.0.7\"})",
496 | "refId": "A"
497 | }
498 | ],
499 | "thresholds": [],
500 | "timeFrom": null,
501 | "timeRegions": [],
502 | "timeShift": null,
503 | "title": "Java 11.0.7",
504 | "tooltip": {
505 | "shared": true,
506 | "sort": 0,
507 | "value_type": "individual"
508 | },
509 | "type": "graph",
510 | "xaxis": {
511 | "buckets": null,
512 | "mode": "time",
513 | "name": null,
514 | "show": true,
515 | "values": []
516 | },
517 | "yaxes": [
518 | {
519 | "decimals": 0,
520 | "format": "short",
521 | "label": null,
522 | "logBase": 1,
523 | "max": null,
524 | "min": "0",
525 | "show": true
526 | },
527 | {
528 | "format": "short",
529 | "label": null,
530 | "logBase": 1,
531 | "max": null,
532 | "min": null,
533 | "show": true
534 | }
535 | ],
536 | "yaxis": {
537 | "align": false,
538 | "alignLevel": null
539 | }
540 | },
541 | {
542 | "aliasColors": {},
543 | "bars": false,
544 | "dashLength": 10,
545 | "dashes": false,
546 | "datasource": null,
547 | "fill": 1,
548 | "fillGradient": 0,
549 | "gridPos": {
550 | "h": 8,
551 | "w": 9,
552 | "x": 13,
553 | "y": 8
554 | },
555 | "hiddenSeries": false,
556 | "id": 8,
557 | "legend": {
558 | "avg": false,
559 | "current": false,
560 | "max": false,
561 | "min": false,
562 | "show": false,
563 | "total": false,
564 | "values": false
565 | },
566 | "lines": true,
567 | "linewidth": 2,
568 | "nullPointMode": "null as zero",
569 | "options": {
570 | "dataLinks": []
571 | },
572 | "percentage": false,
573 | "pointradius": 2,
574 | "points": false,
575 | "renderer": "flot",
576 | "seriesOverrides": [],
577 | "spaceLength": 10,
578 | "stack": false,
579 | "steppedLine": false,
580 | "targets": [
581 | {
582 | "expr": "sum(app_info_total{openssl_version=\"OpenSSL 1.1.1 11 Sep 2018 built on: Tue Nov 12 16:58:35 2019 UTC\"})",
583 | "refId": "A"
584 | }
585 | ],
586 | "thresholds": [],
587 | "timeFrom": null,
588 | "timeRegions": [],
589 | "timeShift": null,
590 | "title": "OpenSSL Nov 2019",
591 | "tooltip": {
592 | "shared": true,
593 | "sort": 0,
594 | "value_type": "individual"
595 | },
596 | "type": "graph",
597 | "xaxis": {
598 | "buckets": null,
599 | "mode": "time",
600 | "name": null,
601 | "show": true,
602 | "values": []
603 | },
604 | "yaxes": [
605 | {
606 | "decimals": 0,
607 | "format": "short",
608 | "label": null,
609 | "logBase": 1,
610 | "max": null,
611 | "min": "0",
612 | "show": true
613 | },
614 | {
615 | "format": "short",
616 | "label": null,
617 | "logBase": 1,
618 | "max": null,
619 | "min": null,
620 | "show": true
621 | }
622 | ],
623 | "yaxis": {
624 | "align": false,
625 | "alignLevel": null
626 | }
627 | }
628 | ],
629 | "refresh": "10s",
630 | "schemaVersion": 21,
631 | "style": "dark",
632 | "tags": [],
633 | "templating": {
634 | "list": []
635 | },
636 | "time": {
637 | "from": "now-30m",
638 | "to": "now"
639 | },
640 | "timepicker": {
641 | "refresh_intervals": [
642 | "5s",
643 | "10s",
644 | "30s",
645 | "1m",
646 | "5m",
647 | "15m",
648 | "30m",
649 | "1h",
650 | "2h",
651 | "1d"
652 | ]
653 | },
654 | "timezone": "",
655 | "title": "kpack at scale",
656 | "uid": "DOcXpv8Zz",
657 | "version": 3
658 | }
--------------------------------------------------------------------------------
/k8s/cnb-javawar.yml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: cnb-javawar
5 | ---
6 | apiVersion: apps/v1
7 | kind: Deployment
8 | metadata:
9 | name: app
10 | namespace: cnb-javawar
11 | spec:
12 | replicas: 1
13 | selector:
14 | matchLabels:
15 | app: cnb-javawar
16 | template:
17 | metadata:
18 | labels:
19 | app: cnb-javawar
20 | annotations:
21 | prometheus.io/scrape: "true"
22 | prometheus.io/path: "/metrics"
23 | prometheus.io/port: "8080"
24 | spec:
25 | containers:
26 | - image: alexandreroman/cnb-javawar-kpack
27 | name: app
28 | resources:
29 | limits:
30 | memory: 1Gi
31 | ports:
32 | - containerPort: 8080
33 | livenessProbe:
34 | httpGet:
35 | port: 8080
36 | path: /api/info
37 | initialDelaySeconds: 60
38 | periodSeconds: 2
39 | readinessProbe:
40 | httpGet:
41 | port: 8080
42 | path: /api/info
43 | initialDelaySeconds: 10
44 | ---
45 | apiVersion: v1
46 | kind: Service
47 | metadata:
48 | name: app
49 | namespace: cnb-javawar
50 | labels:
51 | app: cnb-javawar
52 | spec:
53 | type: LoadBalancer
54 | ports:
55 | - port: 80
56 | protocol: TCP
57 | targetPort: 8080
58 | selector:
59 | app: cnb-javawar
60 |
--------------------------------------------------------------------------------
/k8s/cnb-nodejs.yml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: cnb-nodejs
5 | ---
6 | apiVersion: apps/v1
7 | kind: Deployment
8 | metadata:
9 | name: app
10 | namespace: cnb-nodejs
11 | spec:
12 | replicas: 1
13 | selector:
14 | matchLabels:
15 | app: cnb-nodejs
16 | template:
17 | metadata:
18 | labels:
19 | app: cnb-nodejs
20 | annotations:
21 | prometheus.io/scrape: "true"
22 | prometheus.io/path: "/metrics"
23 | prometheus.io/port: "8080"
24 | spec:
25 | containers:
26 | - image: alexandreroman/cnb-nodejs-kpack
27 | name: app
28 | resources:
29 | limits:
30 | memory: 1Gi
31 | ports:
32 | - containerPort: 8080
33 | livenessProbe:
34 | httpGet:
35 | port: 8080
36 | path: /info
37 | initialDelaySeconds: 30
38 | periodSeconds: 2
39 | readinessProbe:
40 | httpGet:
41 | port: 8080
42 | path: /info
43 | initialDelaySeconds: 5
44 | ---
45 | apiVersion: v1
46 | kind: Service
47 | metadata:
48 | name: app
49 | namespace: cnb-nodejs
50 | labels:
51 | app: cnb-nodejs
52 | spec:
53 | type: LoadBalancer
54 | ports:
55 | - port: 80
56 | protocol: TCP
57 | targetPort: 8080
58 | selector:
59 | app: cnb-nodejs
60 |
--------------------------------------------------------------------------------
/k8s/cnb-springboot.yml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: cnb-springboot
5 | ---
6 | apiVersion: apps/v1
7 | kind: Deployment
8 | metadata:
9 | name: app
10 | namespace: cnb-springboot
11 | spec:
12 | replicas: 1
13 | selector:
14 | matchLabels:
15 | app: cnb-springboot
16 | template:
17 | metadata:
18 | labels:
19 | app: cnb-springboot
20 | annotations:
21 | prometheus.io/scrape: "true"
22 | prometheus.io/path: "/actuator/prometheus"
23 | prometheus.io/port: "8080"
24 | spec:
25 | containers:
26 | - image: alexandreroman/cnb-springboot-kpack
27 | name: app
28 | resources:
29 | limits:
30 | memory: 1Gi
31 | ports:
32 | - containerPort: 8080
33 | livenessProbe:
34 | httpGet:
35 | port: 8080
36 | path: /actuator/health
37 | initialDelaySeconds: 60
38 | periodSeconds: 2
39 | readinessProbe:
40 | httpGet:
41 | port: 8080
42 | path: /actuator/health
43 | initialDelaySeconds: 10
44 | ---
45 | apiVersion: v1
46 | kind: Service
47 | metadata:
48 | name: app
49 | namespace: cnb-springboot
50 | labels:
51 | app: cnb-springboot
52 | spec:
53 | type: LoadBalancer
54 | ports:
55 | - port: 80
56 | protocol: TCP
57 | targetPort: 8080
58 | selector:
59 | app: cnb-springboot
60 |
--------------------------------------------------------------------------------
/kpack/01-namespace.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: Namespace
4 | metadata:
5 | name: kpack-builders
6 |
--------------------------------------------------------------------------------
/kpack/02-service-account.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: ServiceAccount
4 | metadata:
5 | name: kpack-service-account
6 | namespace: kpack-builders
7 | secrets:
8 | - name: dockerhub-creds
9 | - name: github-creds
10 |
--------------------------------------------------------------------------------
/kpack/03-custom-stack.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: experimental.kpack.pivotal.io/v1alpha1
3 | kind: Stack
4 | metadata:
5 | name: bionic-stack
6 | namespace: kpack-builders
7 | spec:
8 | id: "io.buildpacks.stacks.bionic"
9 | buildImage:
10 | image: "cloudfoundry/build:0.0.1-base-cnb"
11 | runImage:
12 | image: "cloudfoundry/run:0.0.1-base-cnb"
13 |
--------------------------------------------------------------------------------
/kpack/04-custom-java-builder.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: experimental.kpack.pivotal.io/v1alpha1
3 | kind: Store
4 | metadata:
5 | name: custom-java-store
6 | namespace: kpack-builders
7 | spec:
8 | sources:
9 | - image: cloudfoundry/cnb:0.0.81-bionic
10 | ---
11 | apiVersion: experimental.kpack.pivotal.io/v1alpha1
12 | kind: CustomBuilder
13 | metadata:
14 | name: custom-java-builder
15 | namespace: kpack-builders
16 | spec:
17 | tag: alexandreroman/kpack-custom-java-builder
18 | serviceAccount: kpack-service-account
19 | stack: bionic-stack
20 | store: custom-java-store
21 | order:
22 | - group:
23 | - id: org.cloudfoundry.openjdk
24 | - id: org.cloudfoundry.buildsystem
25 | optional: true
26 | - id: org.cloudfoundry.jvmapplication
27 | optional: true
28 | - id: org.cloudfoundry.tomcat
29 | optional: true
30 | - id: org.cloudfoundry.springboot
31 | optional: true
32 | - id: org.cloudfoundry.distzip
33 | optional: true
34 |
--------------------------------------------------------------------------------
/kpack/05-custom-nodejs-builder.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: experimental.kpack.pivotal.io/v1alpha1
3 | kind: Store
4 | metadata:
5 | name: custom-nodejs-store
6 | namespace: kpack-builders
7 | spec:
8 | sources:
9 | - image: gcr.io/paketo-buildpacks/builder:base
10 | ---
11 | apiVersion: experimental.kpack.pivotal.io/v1alpha1
12 | kind: CustomBuilder
13 | metadata:
14 | name: custom-nodejs-builder
15 | namespace: kpack-builders
16 | spec:
17 | tag: alexandreroman/kpack-custom-nodejs-builder
18 | serviceAccount: kpack-service-account
19 | stack: bionic-stack
20 | store: custom-nodejs-store
21 | order:
22 | - group:
23 | - id: paketo-buildpacks/nodejs
24 | - id: paketo-buildpacks/node-engine
25 | - id: paketo-buildpacks/npm
26 |
--------------------------------------------------------------------------------
/kpack/credentials/dockerhub-creds.template.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: Namespace
4 | metadata:
5 | name: kpack-builders
6 | ---
7 | apiVersion: v1
8 | kind: Secret
9 | metadata:
10 | name: dockerhub-creds
11 | namespace: kpack-builders
12 | annotations:
13 | build.pivotal.io/docker: https://index.docker.io/v1/
14 | type: kubernetes.io/basic-auth
15 | stringData:
16 | username:
17 | password:
18 |
--------------------------------------------------------------------------------
/kpack/credentials/github-creds.template.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: Namespace
4 | metadata:
5 | name: kpack-builders
6 | ---
7 | apiVersion: v1
8 | kind: Secret
9 | metadata:
10 | name: github-creds
11 | namespace: kpack-builders
12 | annotations:
13 | build.pivotal.io/git: https://github.com
14 | type: kubernetes.io/basic-auth
15 | stringData:
16 | username:
17 | password:
18 |
--------------------------------------------------------------------------------
/kpack/images/cnb-javawar-image.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: build.pivotal.io/v1alpha1
3 | kind: Image
4 | metadata:
5 | name: cnb-javawar
6 | namespace: kpack-builders
7 | spec:
8 | tag: alexandreroman/cnb-javawar-kpack
9 | serviceAccount: kpack-service-account
10 | builder:
11 | name: custom-java-builder
12 | kind: CustomBuilder
13 | cacheSize: "2Gi"
14 | source:
15 | git:
16 | url: https://github.com/alexandreroman/cnb-javawar.git
17 | revision: testing
18 |
--------------------------------------------------------------------------------
/kpack/images/cnb-nodejs-image.yml:
--------------------------------------------------------------------------------
1 | apiVersion: build.pivotal.io/v1alpha1
2 | kind: Image
3 | metadata:
4 | name: cnb-nodejs
5 | namespace: kpack-builders
6 | spec:
7 | tag: alexandreroman/cnb-nodejs-kpack
8 | serviceAccount: kpack-service-account
9 | builder:
10 | name: custom-nodejs-builder
11 | kind: CustomBuilder
12 | cacheSize: "2Gi"
13 | source:
14 | git:
15 | url: https://github.com/alexandreroman/cnb-nodejs.git
16 | revision: testing
17 |
--------------------------------------------------------------------------------
/kpack/images/cnb-springboot-image.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: build.pivotal.io/v1alpha1
3 | kind: Image
4 | metadata:
5 | name: cnb-springboot
6 | namespace: kpack-builders
7 | spec:
8 | tag: alexandreroman/cnb-springboot-kpack
9 | serviceAccount: kpack-service-account
10 | builder:
11 | name: custom-java-builder
12 | kind: CustomBuilder
13 | cacheSize: "2Gi"
14 | source:
15 | git:
16 | url: https://github.com/alexandreroman/cnb-springboot.git
17 | revision: testing
18 |
--------------------------------------------------------------------------------
/kpack/jvm-update/jvm-update.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: experimental.kpack.pivotal.io/v1alpha1
3 | kind: Store
4 | metadata:
5 | name: custom-java-store
6 | namespace: kpack-builders
7 | spec:
8 | sources:
9 | - image: gcr.io/paketo-buildpacks/builder:0.0.100-bionic
10 | ---
11 | apiVersion: experimental.kpack.pivotal.io/v1alpha1
12 | kind: CustomBuilder
13 | metadata:
14 | name: custom-java-builder
15 | namespace: kpack-builders
16 | spec:
17 | tag: alexandreroman/kpack-custom-java-builder
18 | serviceAccount: kpack-service-account
19 | stack: bionic-stack
20 | store: custom-java-store
21 | order:
22 | - group:
23 | - id: paketo-buildpacks/bellsoft-liberica
24 | - id: paketo-buildpacks/build-system
25 | optional: true
26 | - id: paketo-buildpacks/executable-jar
27 | optional: true
28 | - id: paketo-buildpacks/apache-tomcat
29 | optional: true
30 | - id: paketo-buildpacks/spring-boot
31 | optional: true
32 | - id: paketo-buildpacks/dist-zip
33 | optional: true
34 |
--------------------------------------------------------------------------------
/kpack/latest/jvm-latest.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: experimental.kpack.pivotal.io/v1alpha1
3 | kind: Store
4 | metadata:
5 | name: custom-java-store
6 | namespace: kpack-builders
7 | spec:
8 | sources:
9 | - image: gcr.io/paketo-buildpacks/builder:base
10 | ---
11 | apiVersion: experimental.kpack.pivotal.io/v1alpha1
12 | kind: CustomBuilder
13 | metadata:
14 | name: custom-java-builder
15 | namespace: kpack-builders
16 | spec:
17 | tag: alexandreroman/kpack-custom-java-builder
18 | serviceAccount: kpack-service-account
19 | stack: bionic-stack
20 | store: custom-java-store
21 | order:
22 | - group:
23 | - id: paketo-buildpacks/bellsoft-liberica
24 | - id: paketo-buildpacks/maven
25 | optional: true
26 | - id: paketo-buildpacks/executable-jar
27 | optional: true
28 | - id: paketo-buildpacks/apache-tomcat
29 | optional: true
30 | - id: paketo-buildpacks/spring-boot
31 | optional: true
32 | - id: paketo-buildpacks/dist-zip
33 | optional: true
34 |
--------------------------------------------------------------------------------
/kpack/latest/stack-latest.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: experimental.kpack.pivotal.io/v1alpha1
3 | kind: Stack
4 | metadata:
5 | name: bionic-stack
6 | namespace: kpack-builders
7 | spec:
8 | id: "io.buildpacks.stacks.bionic"
9 | buildImage:
10 | image: "gcr.io/paketo-buildpacks/build:base-cnb"
11 | runImage:
12 | image: "gcr.io/paketo-buildpacks/run:base-cnb"
13 |
--------------------------------------------------------------------------------
/kpack/stack-update/stack-update.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: experimental.kpack.pivotal.io/v1alpha1
3 | kind: Stack
4 | metadata:
5 | name: bionic-stack
6 | namespace: kpack-builders
7 | spec:
8 | id: "io.buildpacks.stacks.bionic"
9 | buildImage:
10 | image: "gcr.io/paketo-buildpacks/build:0.0.12-base-cnb"
11 | runImage:
12 | image: "gcr.io/paketo-buildpacks/run:0.0.13-base-cnb"
13 |
--------------------------------------------------------------------------------