├── .circleci └── config.yml ├── LICENSE ├── README.md ├── charts └── ghost │ ├── .helmignore │ ├── Chart.yaml │ ├── OWNERS │ ├── README.md │ ├── requirements.lock │ ├── requirements.yaml │ ├── templates │ ├── NOTES.txt │ ├── _helpers.tpl │ ├── deployment.yaml │ ├── ingress.yaml │ ├── pvc.yaml │ ├── secrets.yaml │ └── svc.yaml │ ├── values.schema.json │ └── values.yaml ├── namespaces └── demo.yaml ├── releases ├── ghost.yaml ├── mongodb.yaml ├── redis-auth.yaml └── redis.yaml └── workloads ├── podinfo-dep.yaml ├── podinfo-hpa.yaml └── podinfo-svc.yaml /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | jobs: 3 | validate-yamls: 4 | docker: 5 | - image: stefanprodan/hrval:v2.9.0 6 | steps: 7 | - checkout 8 | - run: 9 | name: Validate workloads 10 | environment: 11 | KUBE_VER: "1.16.0" 12 | command: | 13 | kubeval --strict --ignore-missing-schemas --kubernetes-version ${KUBE_VER} -d namespaces,workloads,releases 14 | - run: 15 | name: Validate releases 16 | environment: 17 | IGNORE_VALUES: "false" 18 | KUBE_VER: "1.16.0" 19 | HELM_VER: "v2" 20 | command: | 21 | hrval releases/ $IGNORE_VALUES $KUBE_VER $HELM_VER 22 | 23 | workflows: 24 | version: 2 25 | validate: 26 | jobs: 27 | - validate-yamls: 28 | filters: 29 | branches: 30 | ignore: 31 | - gh-pages 32 | -------------------------------------------------------------------------------- /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 | # flux-get-started 2 | 3 | ## We are moving to Flux v2 4 | 5 | > ⚠️ Please note: In preparation of [Flux v2](https://toolkit.fluxcd.io/) GA this repository with Flux v1 examples has been archived. The Flux v2 equivalent of what is shown here can be found at [flux2-kustomize-helm-example](https://github.com/fluxcd/flux2-kustomize-helm-example). 6 | > 7 | > Thanks a lot for your interest. 8 | 9 | ## For posterity 10 | 11 | We published a step-by-step run-through on how to use Flux and Helm Operator [over 12 | here](https://github.com/fluxcd/flux/blob/master/docs/tutorials/get-started-helm.md). 13 | 14 | ## Workloads 15 | 16 | [podinfo](https://github.com/stefanprodan/podinfo) 17 | * Kubernetes deployment, ClusterIP service and Horizontal Pod Autoscaler 18 | * init container automated image updates (regular expression filter) 19 | * container automated image updates (semantic versioning filter) 20 | 21 | ## Helm Releases 22 | 23 | Mongodb 24 | * Source: Helm repository (stable) 25 | * Kubernetes deployment 26 | * automated image updates (semantic versioning filter) 27 | 28 | Redis 29 | * Source: Helm repository (stable) 30 | * Kubernetes stateful set 31 | * locked automated image updates (semantic versioning filter) 32 | 33 | Ghost 34 | * Source: Git repository 35 | * disabled automated image updates (glob filter) 36 | * has external dependency - mariadb (stable) 37 | 38 | ## Manifests Validation 39 | 40 | CircleCI [jobs](./.circleci/config.yml): 41 | * validate Kubernetes manifests with [kubeval](https://github.com/instrumenta/kubeval) 42 | * validate Flux Helm Releases with [hrval](https://github.com/stefanprodan/hrval-action) 43 | 44 | ### Getting Help 45 | 46 | If you have any questions about, feedback for or problems with `flux-get-started`: 47 | 48 | 49 | - Invite yourself to the CNCF community 50 | slack and ask a question on the [#flux](https://cloud-native.slack.com/messages/flux/) 51 | channel. 52 | - To be part of the conversation about Flux's development, join the 53 | [flux-dev mailing list](https://lists.cncf.io/g/cncf-flux-dev). 54 | - [File an issue.](https://github.com/fluxcd/flux/issues/new) 55 | 56 | Your feedback is always welcome! 57 | -------------------------------------------------------------------------------- /charts/ghost/.helmignore: -------------------------------------------------------------------------------- 1 | .git 2 | -------------------------------------------------------------------------------- /charts/ghost/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | name: ghost 3 | version: 9.0.4 4 | appVersion: 3.1.1 5 | description: A simple, powerful publishing platform that allows you to share your stories with the world 6 | keywords: 7 | - ghost 8 | - blog 9 | - http 10 | - web 11 | - application 12 | - nodejs 13 | - javascript 14 | home: http://www.ghost.org/ 15 | icon: https://bitnami.com/assets/stacks/ghost/img/ghost-stack-220x234.png 16 | sources: 17 | - https://github.com/bitnami/bitnami-docker-ghost 18 | maintainers: 19 | - name: Bitnami 20 | email: containers@bitnami.com 21 | engine: gotpl 22 | -------------------------------------------------------------------------------- /charts/ghost/OWNERS: -------------------------------------------------------------------------------- 1 | approvers: 2 | - prydonius 3 | - tompizmor 4 | - sameersbn 5 | - carrodher 6 | - javsalgar 7 | - juan131 8 | - miguelaeh 9 | reviewers: 10 | - prydonius 11 | - tompizmor 12 | - sameersbn 13 | - carrodher 14 | - javsalgar 15 | - juan131 16 | - miguelaeh 17 | -------------------------------------------------------------------------------- /charts/ghost/README.md: -------------------------------------------------------------------------------- 1 | # Ghost 2 | 3 | [Ghost](https://ghost.org/) is one of the most versatile open source content management systems on the market. 4 | 5 | ## TL;DR; 6 | 7 | ```console 8 | $ helm install stable/ghost 9 | ``` 10 | 11 | ## Introduction 12 | 13 | This chart bootstraps a [Ghost](https://github.com/bitnami/bitnami-docker-ghost) deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. 14 | 15 | It also packages the [Bitnami MariaDB chart](https://github.com/kubernetes/charts/tree/master/stable/mariadb) which is required for bootstrapping a MariaDB deployment for the database requirements of the Ghost application. 16 | 17 | Bitnami charts can be used with [Kubeapps](https://kubeapps.com/) for deployment and management of Helm Charts in clusters. This chart has been tested to work with NGINX Ingress, cert-manager, fluentd and Prometheus on top of the [BKPR](https://kubeprod.io/). 18 | 19 | ## Prerequisites 20 | 21 | - Kubernetes 1.12+ 22 | - Helm 2.11+ or Helm 3.0-beta3+ 23 | - PV provisioner support in the underlying infrastructure 24 | - ReadWriteMany volumes for deployment scaling 25 | 26 | ## Installing the Chart 27 | 28 | To install the chart with the release name `my-release`: 29 | 30 | ```console 31 | $ helm install --name my-release stable/ghost 32 | ``` 33 | 34 | The command deploys Ghost on the Kubernetes cluster in the default configuration. The [Parameters](#parameters) section lists the parameters that can be configured during installation. 35 | 36 | > **Tip**: List all releases using `helm list` 37 | 38 | ## Uninstalling the Chart 39 | 40 | To uninstall/delete the `my-release` deployment: 41 | 42 | ```console 43 | $ helm delete my-release 44 | ``` 45 | 46 | The command removes all the Kubernetes components associated with the chart and deletes the release. 47 | 48 | ## Parameters 49 | 50 | The following table lists the configurable parameters of the Ghost chart and their default values. 51 | 52 | | Parameter | Description | Default | 53 | |-------------------------------------|---------------------------------------------------------------|----------------------------------------------------------| 54 | | `global.imageRegistry` | Global Docker image registry | `nil` | 55 | | `global.imagePullSecrets` | Global Docker registry secret names as an array | `[]` (does not add image pull secrets to deployed pods) | 56 | | `global.storageClass` | Global storage class for dynamic provisioning | `nil` | 57 | | `image.registry` | Ghost image registry | `docker.io` | 58 | | `image.repository` | Ghost Image name | `bitnami/ghost` | 59 | | `image.tag` | Ghost Image tag | `{TAG_NAME}` | 60 | | `image.pullPolicy` | Image pull policy | `IfNotPresent` | 61 | | `image.pullSecrets` | Specify docker-registry secret names as an array | `[]` (does not add image pull secrets to deployed pods) | 62 | | `nameOverride` | String to partially override ghost.fullname template with a string (will prepend the release name) | `nil` | 63 | | `fullnameOverride` | String to fully override ghost.fullname template with a string | `nil` | 64 | | `volumePermissions.image.registry` | Init container volume-permissions image registry | `docker.io` | 65 | | `volumePermissions.image.repository`| Init container volume-permissions image name | `bitnami/minideb` | 66 | | `volumePermissions.image.tag` | Init container volume-permissions image tag | `stretch` | 67 | | `volumePermissions.image.pullPolicy`| Init container volume-permissions image pull policy | `Always` | 68 | | `ghostHost` | Ghost host to create application URLs | `nil` | 69 | | `ghostPort` | Ghost port to use in application URLs (defaults to `service.port` if `nil`) | `nil` | 70 | | `ghostProtocol` | Protocol (http or https) to use in the application URLs | `http` | 71 | | `ghostPath` | Ghost path to create application URLs | `nil` | 72 | | `ghostUsername` | User of the application | `user@example.com` | 73 | | `ghostPassword` | Application password | Randomly generated | 74 | | `ghostEmail` | Admin email | `user@example.com` | 75 | | `ghostBlogTitle` | Ghost Blog name | `User's Blog` | 76 | | `smtpHost` | SMTP host | `nil` | 77 | | `smtpPort` | SMTP port | `nil` | 78 | | `smtpUser` | SMTP user | `nil` | 79 | | `smtpPassword` | SMTP password | `nil` | 80 | | `smtpFromAddress` | SMTP from address | `nil` | 81 | | `smtpService` | SMTP service | `nil` | 82 | | `allowEmptyPassword` | Allow DB blank passwords | `yes` | 83 | | `securityContext.enabled` | Enable security context | `true` | 84 | | `securityContext.fsGroup` | Group ID for the container | `1001` | 85 | | `securityContext.runAsUser` | User ID for the container | `1001` | 86 | | `service.type` | Kubernetes Service type | `LoadBalancer` | 87 | | `service.port` | Service HTTP port | `80` | 88 | | `service.nodePorts.http` | Kubernetes http node port | `""` | 89 | | `service.externalTrafficPolicy` | Enable client source IP preservation | `Cluster` | 90 | | `service.loadBalancerIP` | LoadBalancerIP for the Ghost service | `` | 91 | | `service.annotations` | Service annotations | `` | 92 | | `ingress.enabled` | Enable ingress controller resource | `false` | 93 | | `ingress.annotations` | Ingress annotations | `[]` | 94 | | `ingress.certManager` | Add annotations for cert-manager | `false` | 95 | | `ingress.hosts[0].name` | Hostname to your Ghost installation | `ghost.local` | 96 | | `ingress.hosts[0].path` | Path within the url structure | `/` | 97 | | `ingress.hosts[0].tls` | Utilize TLS backend in ingress | `false` | 98 | | `ingress.hosts[0].tlsHosts` | Array of TLS hosts for ingress record (defaults to `ingress.hosts[0].name` if `nil`) | `nil` | 99 | | `ingress.hosts[0].tlsSecret` | TLS Secret (certificates) | `ghost.local-tls-secret` | 100 | | `ingress.secrets[0].name` | TLS Secret Name | `nil` | 101 | | `ingress.secrets[0].certificate` | TLS Secret Certificate | `nil` | 102 | | `ingress.secrets[0].key` | TLS Secret Key | `nil` | 103 | | `externalDatabase.host` | Host of the external database | `localhost` | 104 | | `externalDatabase.port` | Port of the external database | `3306` | 105 | | `externalDatabase.user` | Existing username in the external db | `bn_ghost` | 106 | | `externalDatabase.password` | Password for the above username | `""` | 107 | | `externalDatabase.database` | Name of the existing database | `bitnami_ghost` | 108 | | `mariadb.enabled` | Whether or not to install MariaDB (disable if using external) | `true` | 109 | | `mariadb.rootUser.password` | MariaDB admin password | `nil` | 110 | | `mariadb.db.name` | MariaDB Database name to create | `bitnami_ghost` | 111 | | `mariadb.db.user` | MariaDB Database user to create | `bn_ghost` | 112 | | `mariadb.db.password` | MariaDB Password for user | _random 10 character long alphanumeric string_ | 113 | | `persistence.enabled` | Enable persistence using PVC | `true` | 114 | | `persistence.storageClass` | PVC Storage Class for Ghost volume | `nil` (uses alpha storage annotation) | 115 | | `persistence.accessMode` | PVC Access Mode for Ghost volume | `ReadWriteOnce` | 116 | | `persistence.size` | PVC Storage Request for Ghost volume | `8Gi` | 117 | | `persistence.path` | Path to mount the volume at, to use other images | `/bitnami` | 118 | | `resources` | CPU/Memory resource requests/limits | Memory: `512Mi`, CPU: `300m` | 119 | | `nodeSelector` | Node selector for pod assignment | `{}` | 120 | | `affinity` | Map of node/pod affinities | `{}` | 121 | 122 | The above parameters map to the env variables defined in [bitnami/ghost](http://github.com/bitnami/bitnami-docker-ghost). For more information please refer to the [bitnami/ghost](http://github.com/bitnami/bitnami-docker-ghost) image documentation. 123 | 124 | > **Note**: 125 | > 126 | > For the Ghost application function correctly, you should specify the `ghostHost` parameter to specify the FQDN (recommended) or the public IP address of the Ghost service. 127 | > 128 | > Optionally, you can specify the `ghostLoadBalancerIP` parameter to assign a reserved IP address to the Ghost service of the chart. However please note that this feature is only available on a few cloud providers (f.e. GKE). 129 | > 130 | > To reserve a public IP address on GKE: 131 | > 132 | > ```bash 133 | > $ gcloud compute addresses create ghost-public-ip 134 | > ``` 135 | > 136 | > The reserved IP address can be assigned to the Ghost service by specifying it as the value of the `ghostLoadBalancerIP` parameter while installing the chart. 137 | 138 | Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, 139 | 140 | ```console 141 | $ helm install --name my-release \ 142 | --set ghostUsername=admin,ghostPassword=password,mariadb.mariadbRootPassword=secretpassword \ 143 | stable/ghost 144 | ``` 145 | 146 | The above command sets the Ghost administrator account username and password to `admin` and `password` respectively. Additionally, it sets the MariaDB `root` user password to `secretpassword`. 147 | 148 | Alternatively, a YAML file that specifies the values for the above parameters can be provided while installing the chart. For example, 149 | 150 | ```console 151 | $ helm install --name my-release -f values.yaml stable/ghost 152 | ``` 153 | 154 | > **Tip**: You can use the default [values.yaml](values.yaml) 155 | 156 | ## Configuration and installation details 157 | 158 | ### [Rolling VS Immutable tags](https://docs.bitnami.com/containers/how-to/understand-rolling-tags-containers/) 159 | 160 | It is strongly recommended to use immutable tags in a production environment. This ensures your deployment does not change automatically if the same tag is updated with a different image. 161 | 162 | Bitnami will release a new chart updating its containers if a new version of the main container, significant changes, or critical vulnerabilities exist. 163 | 164 | ### Using an existing database 165 | 166 | Sometimes you may want to have Ghost connect to an external database rather than installing one inside your cluster, e.g. to use a managed database service, or use run a single database server for all your applications. To do this, the chart allows you to specify credentials for an external database under the [`externalDatabase` parameter](#parameters). You should also disable the MariaDB installation with the `mariadb.enabled` option. For example using the following parameters: 167 | 168 | ```console 169 | mariadb.enabled=false 170 | externalDatabase.host=myexternalhost 171 | externalDatabase.user=myuser 172 | externalDatabase.password=mypassword 173 | externalDatabase.database=mydatabase 174 | ``` 175 | 176 | ## Persistence 177 | 178 | The [Bitnami Ghost](https://github.com/bitnami/bitnami-docker-ghost) image stores the Ghost data and configurations at the `/bitnami/ghost` and `/bitnami/apache` paths of the container. 179 | 180 | Persistent Volume Claims are used to keep the data across deployments. This is known to work in GCE, AWS, and minikube. 181 | See the [Parameters](#parameters) section to configure the PVC or to disable persistence. 182 | 183 | ## Upgrading 184 | 185 | ### To 9.0.0 186 | 187 | Helm performs a lookup for the object based on its group (apps), version (v1), and kind (Deployment). Also known as its GroupVersionKind, or GVK. Changing the GVK is considered a compatibility breaker from Kubernetes' point of view, so you cannot "upgrade" those objects to the new GVK in-place. Earlier versions of Helm 3 did not perform the lookup correctly which has since been fixed to match the spec. 188 | 189 | In https://github.com/helm/charts/pulls/17297 the `apiVersion` of the deployment resources was updated to `apps/v1` in tune with the api's deprecated, resulting in compatibility breakage. 190 | 191 | This major version signifies this change. 192 | 193 | ### To 5.0.0 194 | 195 | Backwards compatibility is not guaranteed unless you modify the labels used on the chart's deployments. 196 | Use the workaround below to upgrade from versions previous to 5.0.0. The following example assumes that the release name is ghost: 197 | 198 | ```console 199 | $ kubectl patch deployment ghost-ghost --type=json -p='[{"op": "remove", "path": "/spec/selector/matchLabels/chart"}]' 200 | $ kubectl delete statefulset ghost-mariadb --cascade=false 201 | ``` 202 | -------------------------------------------------------------------------------- /charts/ghost/requirements.lock: -------------------------------------------------------------------------------- 1 | dependencies: 2 | - name: mariadb 3 | repository: https://charts.helm.sh/stable 4 | version: 7.3.14 5 | digest: sha256:44ec62c7893a6de23b0121d2a6e4d9aae63b4dd5399367847a56b4714ffb71f4 6 | generated: "2021-01-14T21:40:03.752300326+01:00" 7 | -------------------------------------------------------------------------------- /charts/ghost/requirements.yaml: -------------------------------------------------------------------------------- 1 | dependencies: 2 | - name: mariadb 3 | version: 7.x.x 4 | repository: https://charts.helm.sh/stable 5 | condition: mariadb.enabled 6 | tags: 7 | - ghost-database 8 | -------------------------------------------------------------------------------- /charts/ghost/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | {{- if empty (include "ghost.host" .) -}} 2 | ############################################################################### 3 | ### ERROR: You did not provide an external host in your 'helm install' call ### 4 | ############################################################################### 5 | 6 | This deployment will be incomplete until you configure Ghost with a resolvable 7 | host. To configure Ghost with the URL of your service: 8 | 9 | 1. Get the Ghost URL by running: 10 | 11 | {{- if contains "NodePort" .Values.service.type }} 12 | 13 | export APP_HOST=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") 14 | 15 | {{- else if contains "LoadBalancer" .Values.service.type }} 16 | 17 | NOTE: It may take a few minutes for the LoadBalancer IP to be available. 18 | Watch the status with: 'kubectl get svc --namespace {{ .Release.Namespace }} -w {{ template "ghost.fullname" . }}' 19 | 20 | export APP_HOST=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "ghost.fullname" . }} --template "{{ "{{ range (index .status.loadBalancer.ingress 0) }}{{ . }}{{ end }}" }}") 21 | export APP_PASSWORD=$(kubectl get secret --namespace {{ .Release.Namespace }} {{ template "ghost.fullname" . }} -o jsonpath="{.data.ghost-password}" | base64 --decode) 22 | {{- if .Values.mariadb.mariadbRootPassword }} 23 | export DATABASE_ROOT_PASSWORD=$(kubectl get secret --namespace {{ .Release.Namespace }} {{ template "ghost.mariadb.fullname" . }} -o jsonpath="{.data.mariadb-root-password}" | base64 --decode) 24 | {{- end }} 25 | {{- end }} 26 | export APP_DATABASE_PASSWORD=$(kubectl get secret --namespace {{ .Release.Namespace }} {{ template "ghost.mariadb.fullname" . }} -o jsonpath="{.data.mariadb-password}" | base64 --decode) 27 | 28 | 2. Complete your Ghost deployment by running: 29 | 30 | helm upgrade {{ .Release.Name }} stable/{{ .Chart.Name }} \ 31 | --set service.type={{ .Values.service.type }},ghostHost=$APP_HOST,ghostPassword=$APP_PASSWORD,{{ if .Values.mariadb.mariadbRootPassword }},mariadb.mariadbRootPassword=$DATABASE_ROOT_PASSWORD{{ end }}mariadb.db.password=$APP_DATABASE_PASSWORD{{- if .Values.global }}{{- if .Values.global.imagePullSecrets }},global.imagePullSecrets={{ .Values.global.imagePullSecrets }}{{- end }}{{- end }} 32 | {{- else -}} 33 | 1. Get the Ghost URL by running: 34 | 35 | {{- if eq .Values.service.type "ClusterIP" }} 36 | 37 | echo Blog URL : http://127.0.0.1:{{ default "80" .Values.service.port }}{{ .Values.ghostPath }} 38 | echo Admin URL : http://127.0.0.1:{{ default "80" .Values.service.port }}{{ .Values.ghostPath }}ghost 39 | kubectl port-forward --namespace {{ .Release.Namespace }} svc/{{ template "ghost.fullname" . }} {{ default "80" .Values.service.port }}:2368 40 | 41 | {{- else if eq .Values.service.type "NodePort" }} 42 | export APP_HOST=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") 43 | export APP_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "ghost.fullname" . }}) 44 | 45 | echo Blog URL : http://$APP_HOST:$APP_PORT{{ .Values.ghostPath }} 46 | echo Admin URL : http://$APP_HOST:$APP_PORT{{ .Values.ghostPath }}ghost 47 | 48 | {{- else }} 49 | 50 | echo Blog URL : http://{{ include "ghost.host" . }} 51 | echo Admin URL : http://{{ include "ghost.host" . }}ghost 52 | {{- end }} 53 | 54 | 2. Get your Ghost login credentials by running: 55 | 56 | echo Email: {{ .Values.ghostEmail }} 57 | echo Password: $(kubectl get secret --namespace {{ .Release.Namespace }} {{ template "ghost.fullname" . }} -o jsonpath="{.data.ghost-password}" | base64 --decode) 58 | {{- end }} 59 | 60 | {{- if and (contains "bitnami/" .Values.image.repository) (not (.Values.image.tag | toString | regexFind "-r\\d+$|sha256:")) }} 61 | 62 | WARNING: Rolling tag detected ({{ .Values.image.repository }}:{{ .Values.image.tag }}), please note that it is strongly recommended to avoid using rolling tags in a production environment. 63 | +info https://docs.bitnami.com/containers/how-to/understand-rolling-tags-containers/ 64 | 65 | {{- end }} 66 | -------------------------------------------------------------------------------- /charts/ghost/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* vim: set filetype=mustache: */}} 2 | {{/* 3 | Expand the name of the chart. 4 | */}} 5 | {{- define "ghost.name" -}} 6 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} 7 | {{- end -}} 8 | 9 | {{/* 10 | Create a default fully qualified app name. 11 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 12 | If release name contains chart name it will be used as a full name. 13 | */}} 14 | {{- define "ghost.fullname" -}} 15 | {{- if .Values.fullnameOverride -}} 16 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} 17 | {{- else -}} 18 | {{- $name := default .Chart.Name .Values.nameOverride -}} 19 | {{- if contains $name .Release.Name -}} 20 | {{- .Release.Name | trunc 63 | trimSuffix "-" -}} 21 | {{- else -}} 22 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} 23 | {{- end -}} 24 | {{- end -}} 25 | {{- end -}} 26 | 27 | {{/* 28 | Create a default fully qualified app name. 29 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 30 | */}} 31 | {{- define "ghost.mariadb.fullname" -}} 32 | {{- printf "%s-%s" .Release.Name "mariadb" | trunc 63 | trimSuffix "-" -}} 33 | {{- end -}} 34 | 35 | {{/* 36 | Get the user defined LoadBalancerIP for this release. 37 | Note, returns 127.0.0.1 if using ClusterIP. 38 | */}} 39 | {{- define "ghost.serviceIP" -}} 40 | {{- if eq .Values.service.type "ClusterIP" -}} 41 | 127.0.0.1 42 | {{- else -}} 43 | {{- .Values.service.loadBalancerIP | default "" -}} 44 | {{- end -}} 45 | {{- end -}} 46 | 47 | {{/* 48 | Gets the host to be used for this application. 49 | If not using ClusterIP, or if a host or LoadBalancerIP is not defined, the value will be empty. 50 | */}} 51 | {{- define "ghost.host" -}} 52 | {{- if .Values.ghostHost -}} 53 | {{- $host := printf "%s%s" .Values.ghostHost .Values.ghostPath -}} 54 | {{- default (include "ghost.serviceIP" .) $host -}} 55 | {{- else -}} 56 | {{- default (include "ghost.serviceIP" .) "" -}} 57 | {{- end -}} 58 | {{- end -}} 59 | 60 | {{/* 61 | Create chart name and version as used by the chart label. 62 | */}} 63 | {{- define "ghost.chart" -}} 64 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} 65 | {{- end -}} 66 | 67 | {{/* 68 | Return the proper Ghost image name 69 | */}} 70 | {{- define "ghost.image" -}} 71 | {{- $registryName := .Values.image.registry -}} 72 | {{- $repositoryName := .Values.image.repository -}} 73 | {{- $tag := .Values.image.tag | toString -}} 74 | {{/* 75 | Helm 2.11 supports the assignment of a value to a variable defined in a different scope, 76 | but Helm 2.9 and 2.10 doesn't support it, so we need to implement this if-else logic. 77 | Also, we can't use a single if because lazy evaluation is not an option 78 | */}} 79 | {{- if .Values.global }} 80 | {{- if .Values.global.imageRegistry }} 81 | {{- printf "%s/%s:%s" .Values.global.imageRegistry $repositoryName $tag -}} 82 | {{- else -}} 83 | {{- printf "%s/%s:%s" $registryName $repositoryName $tag -}} 84 | {{- end -}} 85 | {{- else -}} 86 | {{- printf "%s/%s:%s" $registryName $repositoryName $tag -}} 87 | {{- end -}} 88 | {{- end -}} 89 | 90 | {{/* 91 | Return the proper image name to change the volume permissions 92 | */}} 93 | {{- define "ghost.volumePermissions.image" -}} 94 | {{- $registryName := .Values.volumePermissions.image.registry -}} 95 | {{- $repositoryName := .Values.volumePermissions.image.repository -}} 96 | {{- $tag := .Values.volumePermissions.image.tag | toString -}} 97 | {{/* 98 | Helm 2.11 supports the assignment of a value to a variable defined in a different scope, 99 | but Helm 2.9 and 2.10 doesn't support it, so we need to implement this if-else logic. 100 | Also, we can't use a single if because lazy evaluation is not an option 101 | */}} 102 | {{- if .Values.global }} 103 | {{- if .Values.global.imageRegistry }} 104 | {{- printf "%s/%s:%s" .Values.global.imageRegistry $repositoryName $tag -}} 105 | {{- else -}} 106 | {{- printf "%s/%s:%s" $registryName $repositoryName $tag -}} 107 | {{- end -}} 108 | {{- else -}} 109 | {{- printf "%s/%s:%s" $registryName $repositoryName $tag -}} 110 | {{- end -}} 111 | {{- end -}} 112 | 113 | {{/* 114 | Return the proper Docker Image Registry Secret Names 115 | */}} 116 | {{- define "ghost.imagePullSecrets" -}} 117 | {{/* 118 | Helm 2.11 supports the assignment of a value to a variable defined in a different scope, 119 | but Helm 2.9 and 2.10 does not support it, so we need to implement this if-else logic. 120 | Also, we can not use a single if because lazy evaluation is not an option 121 | */}} 122 | {{- if .Values.global }} 123 | {{- if .Values.global.imagePullSecrets }} 124 | imagePullSecrets: 125 | {{- range .Values.global.imagePullSecrets }} 126 | - name: {{ . }} 127 | {{- end }} 128 | {{- else if or .Values.image.pullSecrets .Values.volumePermissions.image.pullSecrets }} 129 | imagePullSecrets: 130 | {{- range .Values.image.pullSecrets }} 131 | - name: {{ . }} 132 | {{- end }} 133 | {{- range .Values.volumePermissions.image.pullSecrets }} 134 | - name: {{ . }} 135 | {{- end }} 136 | {{- end -}} 137 | {{- else if or .Values.image.pullSecrets .Values.volumePermissions.image.pullSecrets }} 138 | imagePullSecrets: 139 | {{- range .Values.image.pullSecrets }} 140 | - name: {{ . }} 141 | {{- end }} 142 | {{- range .Values.volumePermissions.image.pullSecrets }} 143 | - name: {{ . }} 144 | {{- end }} 145 | {{- end -}} 146 | {{- end -}} 147 | 148 | {{/* 149 | Return the proper Storage Class 150 | */}} 151 | {{- define "ghost.storageClass" -}} 152 | {{/* 153 | Helm 2.11 supports the assignment of a value to a variable defined in a different scope, 154 | but Helm 2.9 and 2.10 does not support it, so we need to implement this if-else logic. 155 | */}} 156 | {{- if .Values.global -}} 157 | {{- if .Values.global.storageClass -}} 158 | {{- if (eq "-" .Values.global.storageClass) -}} 159 | {{- printf "storageClassName: \"\"" -}} 160 | {{- else }} 161 | {{- printf "storageClassName: %s" .Values.global.storageClass -}} 162 | {{- end -}} 163 | {{- else -}} 164 | {{- if .Values.persistence.storageClass -}} 165 | {{- if (eq "-" .Values.persistence.storageClass) -}} 166 | {{- printf "storageClassName: \"\"" -}} 167 | {{- else }} 168 | {{- printf "storageClassName: %s" .Values.persistence.storageClass -}} 169 | {{- end -}} 170 | {{- end -}} 171 | {{- end -}} 172 | {{- else -}} 173 | {{- if .Values.persistence.storageClass -}} 174 | {{- if (eq "-" .Values.persistence.storageClass) -}} 175 | {{- printf "storageClassName: \"\"" -}} 176 | {{- else }} 177 | {{- printf "storageClassName: %s" .Values.persistence.storageClass -}} 178 | {{- end -}} 179 | {{- end -}} 180 | {{- end -}} 181 | {{- end -}} 182 | 183 | {{/* 184 | Return the appropriate apiVersion for deployment. 185 | */}} 186 | {{- define "ghost.deployment.apiVersion" -}} 187 | {{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} 188 | {{- print "extensions/v1beta1" -}} 189 | {{- else -}} 190 | {{- print "apps/v1" -}} 191 | {{- end -}} 192 | {{- end -}} 193 | -------------------------------------------------------------------------------- /charts/ghost/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | {{- if include "ghost.host" . -}} 2 | apiVersion: {{ template "ghost.deployment.apiVersion" . }} 3 | kind: Deployment 4 | metadata: 5 | name: {{ template "ghost.fullname" . }} 6 | labels: 7 | app: "{{ template "ghost.fullname" . }}" 8 | chart: "{{ template "ghost.chart" . }}" 9 | release: {{ .Release.Name | quote }} 10 | heritage: {{ .Release.Service | quote }} 11 | spec: 12 | selector: 13 | matchLabels: 14 | app: "{{ template "ghost.fullname" . }}" 15 | release: {{ .Release.Name | quote }} 16 | replicas: 1 17 | template: 18 | metadata: 19 | labels: 20 | app: "{{ template "ghost.fullname" . }}" 21 | chart: "{{ template "ghost.chart" . }}" 22 | release: {{ .Release.Name | quote }} 23 | spec: 24 | {{- if .Values.securityContext.enabled }} 25 | securityContext: 26 | fsGroup: {{ .Values.securityContext.fsGroup }} 27 | runAsUser: {{ .Values.securityContext.runAsUser }} 28 | {{- else }} 29 | initContainers: 30 | - name: volume-permissions 31 | image: {{ template "ghost.volumePermissions.image" . }} 32 | imagePullPolicy: "{{ .Values.volumePermissions.image.pullPolicy }}" 33 | command: ['sh', '-c', 'chmod -R g+rwX {{ .Values.persistence.path }}'] 34 | volumeMounts: 35 | - mountPath: {{ .Values.persistence.path }} 36 | name: ghost-data 37 | {{- end }} 38 | {{- include "ghost.imagePullSecrets" . | indent 6 }} 39 | containers: 40 | - name: {{ template "ghost.fullname" . }} 41 | image: {{ template "ghost.image" . }} 42 | imagePullPolicy: {{ .Values.image.pullPolicy | quote }} 43 | env: 44 | - name: ALLOW_EMPTY_PASSWORD 45 | {{- if .Values.allowEmptyPassword }} 46 | value: "yes" 47 | {{- else }} 48 | value: "no" 49 | {{- end }} 50 | - name: MARIADB_HOST 51 | {{- if .Values.mariadb.enabled }} 52 | value: {{ template "ghost.mariadb.fullname" . }} 53 | {{- else }} 54 | value: {{ .Values.externalDatabase.host | quote }} 55 | {{- end }} 56 | - name: MARIADB_PORT_NUMBER 57 | {{- if .Values.mariadb.enabled }} 58 | value: "3306" 59 | {{- else }} 60 | value: {{ .Values.externalDatabase.port | quote }} 61 | {{- end }} 62 | - name: GHOST_DATABASE_NAME 63 | {{- if .Values.mariadb.enabled }} 64 | value: {{ .Values.mariadb.db.name | quote }} 65 | {{- else }} 66 | value: {{ .Values.externalDatabase.database | quote }} 67 | {{- end }} 68 | - name: GHOST_DATABASE_USER 69 | {{- if .Values.mariadb.enabled }} 70 | value: {{ .Values.mariadb.db.user | quote }} 71 | {{- else }} 72 | value: {{ .Values.externalDatabase.user | quote }} 73 | {{- end }} 74 | - name: GHOST_DATABASE_PASSWORD 75 | {{- if .Values.mariadb.enabled }} 76 | valueFrom: 77 | secretKeyRef: 78 | name: {{ template "ghost.mariadb.fullname" . }} 79 | key: mariadb-password 80 | {{- else }} 81 | value: {{ .Values.externalDatabase.password | quote }} 82 | {{- end }} 83 | - name: GHOST_HOST 84 | value: {{ include "ghost.host" . | quote }} 85 | - name: GHOST_PROTOCOL 86 | value: {{ .Values.ghostProtocol | quote }} 87 | - name: GHOST_PORT_NUMBER 88 | {{- if .Values.ghostPort }} 89 | value: {{ .Values.ghostPort | quote }} 90 | {{- else }} 91 | value: {{ .Values.service.port | quote }} 92 | {{- end }} 93 | - name: GHOST_USERNAME 94 | value: {{ .Values.ghostUsername | quote }} 95 | - name: GHOST_PASSWORD 96 | valueFrom: 97 | secretKeyRef: 98 | name: {{ template "ghost.fullname" . }} 99 | key: ghost-password 100 | - name: GHOST_EMAIL 101 | value: {{ .Values.ghostEmail | quote }} 102 | - name: BLOG_TITLE 103 | value: {{ .Values.ghostBlogTitle | quote }} 104 | {{- if .Values.smtpHost }} 105 | - name: SMTP_HOST 106 | value: {{ .Values.smtpHost | quote }} 107 | {{- end }} 108 | {{- if .Values.smtpPort }} 109 | - name: SMTP_PORT 110 | value: {{ .Values.smtpPort | quote }} 111 | {{- end }} 112 | {{- if .Values.smtpUser }} 113 | - name: SMTP_USER 114 | value: {{ .Values.smtpUser | quote }} 115 | {{- end }} 116 | {{- if .Values.smtpPassword }} 117 | - name: SMTP_PASSWORD 118 | valueFrom: 119 | secretKeyRef: 120 | name: {{ template "ghost.fullname" . }} 121 | key: smtp-password 122 | {{- end }} 123 | {{- if .Values.smtpFromAddress }} 124 | - name: SMTP_FROM_ADDRESS 125 | value: {{ .Values.smtpFromAddress | quote }} 126 | {{- end }} 127 | {{- if .Values.smtpService }} 128 | - name: SMTP_SERVICE 129 | value: {{ .Values.smtpService | quote }} 130 | {{- end }} 131 | ports: 132 | - name: http 133 | containerPort: 2368 134 | livenessProbe: 135 | httpGet: 136 | path: {{ .Values.ghostPath }} 137 | port: http 138 | httpHeaders: 139 | - name: Host 140 | value: {{ include "ghost.host" . | quote }} 141 | {{- if eq .Values.ghostProtocol "https" }} 142 | - name: X-Forwarded-Proto 143 | value: https 144 | {{- end }} 145 | initialDelaySeconds: 120 146 | timeoutSeconds: 5 147 | failureThreshold: 6 148 | readinessProbe: 149 | httpGet: 150 | path: {{ .Values.ghostPath }} 151 | port: http 152 | httpHeaders: 153 | - name: Host 154 | value: {{ include "ghost.host" . | quote }} 155 | {{- if eq .Values.ghostProtocol "https" }} 156 | - name: X-Forwarded-Proto 157 | value: https 158 | {{- end }} 159 | initialDelaySeconds: 30 160 | timeoutSeconds: 3 161 | periodSeconds: 5 162 | resources: 163 | {{ toYaml .Values.resources | indent 10 }} 164 | volumeMounts: 165 | - name: ghost-data 166 | mountPath: /bitnami/ghost 167 | volumes: 168 | - name: ghost-data 169 | {{- if .Values.persistence.enabled }} 170 | persistentVolumeClaim: 171 | claimName: {{ template "ghost.fullname" . }} 172 | {{- else }} 173 | emptyDir: {} 174 | {{- end }} 175 | {{- with .Values.nodeSelector }} 176 | nodeSelector: 177 | {{- toYaml . | nindent 8 }} 178 | {{- end }} 179 | {{- with .Values.affinity }} 180 | affinity: 181 | {{- toYaml . | nindent 8 }} 182 | {{- end }} 183 | {{- end -}} 184 | -------------------------------------------------------------------------------- /charts/ghost/templates/ingress.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.ingress.enabled }} 2 | apiVersion: extensions/v1beta1 3 | kind: Ingress 4 | metadata: 5 | name: {{ template "ghost.fullname" . }} 6 | labels: 7 | app: "{{ template "ghost.fullname" . }}" 8 | chart: "{{ template "ghost.chart" . }}" 9 | release: {{ .Release.Name | quote }} 10 | heritage: {{ .Release.Service | quote }} 11 | annotations: 12 | {{- if .Values.ingress.certManager }} 13 | kubernetes.io/tls-acme: "true" 14 | {{- end }} 15 | {{- range $key, $value := .Values.ingress.annotations }} 16 | {{ $key }}: {{ $value | quote }} 17 | {{- end }} 18 | spec: 19 | rules: 20 | {{- range .Values.ingress.hosts }} 21 | - host: {{ .name }} 22 | http: 23 | paths: 24 | - path: {{ default "/" .path }} 25 | backend: 26 | serviceName: {{ template "ghost.fullname" $ }} 27 | servicePort: http 28 | {{- end }} 29 | tls: 30 | {{- range .Values.ingress.hosts }} 31 | {{- if .tls }} 32 | - hosts: 33 | {{- if .tlsHosts }} 34 | {{- range $host := .tlsHosts }} 35 | - {{ $host }} 36 | {{- end }} 37 | {{- else }} 38 | - {{ .name }} 39 | {{- end }} 40 | secretName: {{ .tlsSecret }} 41 | {{- end }} 42 | {{- end }} 43 | {{- end }} 44 | -------------------------------------------------------------------------------- /charts/ghost/templates/pvc.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.persistence.enabled -}} 2 | kind: PersistentVolumeClaim 3 | apiVersion: v1 4 | metadata: 5 | name: {{ template "ghost.fullname" . }} 6 | labels: 7 | app: "{{ template "ghost.fullname" . }}" 8 | chart: "{{ template "ghost.chart" . }}" 9 | release: {{ .Release.Name | quote }} 10 | heritage: {{ .Release.Service | quote }} 11 | spec: 12 | accessModes: 13 | - {{ .Values.persistence.accessMode | quote }} 14 | resources: 15 | requests: 16 | storage: {{ .Values.persistence.size | quote }} 17 | {{ include "ghost.storageClass" . }} 18 | {{- end -}} 19 | -------------------------------------------------------------------------------- /charts/ghost/templates/secrets.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: {{ template "ghost.fullname" . }} 5 | labels: 6 | app: "{{ template "ghost.fullname" . }}" 7 | chart: "{{ template "ghost.chart" . }}" 8 | release: {{ .Release.Name | quote }} 9 | heritage: {{ .Release.Service | quote }} 10 | type: Opaque 11 | data: 12 | {{- if .Values.ghostPassword }} 13 | ghost-password: {{ .Values.ghostPassword | b64enc | quote }} 14 | {{- else }} 15 | ghost-password: {{ randAlphaNum 10 | b64enc | quote }} 16 | {{- end }} 17 | {{- if .Values.smtpPassword }} 18 | smtp-password: {{ default "" .Values.smtpPassword | b64enc | quote }} 19 | {{- end }} 20 | -------------------------------------------------------------------------------- /charts/ghost/templates/svc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ template "ghost.fullname" . }} 5 | labels: 6 | app: "{{ template "ghost.fullname" . }}" 7 | chart: "{{ template "ghost.chart" . }}" 8 | release: {{ .Release.Name | quote }} 9 | heritage: {{ .Release.Service | quote }} 10 | annotations: 11 | {{- range $key, $value := .Values.service.annotations }} 12 | {{ $key }}: {{ $value | quote }} 13 | {{- end }} 14 | 15 | spec: 16 | type: {{ .Values.service.type }} 17 | {{- if (or (eq .Values.service.type "LoadBalancer") (eq .Values.service.type "NodePort")) }} 18 | externalTrafficPolicy: {{ .Values.service.externalTrafficPolicy | quote }} 19 | {{- end }} 20 | {{- if eq .Values.service.type "LoadBalancer" }} 21 | loadBalancerIP: {{ default "" .Values.service.loadBalancerIP | quote }} 22 | {{- end }} 23 | ports: 24 | - name: http 25 | port: {{ .Values.service.port }} 26 | targetPort: http 27 | {{- if (and (eq .Values.service.type "NodePort") (not (empty .Values.service.nodePorts.http)))}} 28 | nodePort: {{ .Values.service.nodePorts.http }} 29 | {{- end }} 30 | selector: 31 | app: "{{ template "ghost.fullname" . }}" 32 | -------------------------------------------------------------------------------- /charts/ghost/values.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema#", 3 | "type": "object", 4 | "properties": { 5 | "ghostUsername": { 6 | "type": "string", 7 | "title": "User", 8 | "form": true 9 | }, 10 | "ghostPassword": { 11 | "type": "string", 12 | "title": "Password", 13 | "form": true, 14 | "description": "Defaults to a random 10-character alphanumeric string if not set" 15 | }, 16 | "ghostEmail": { 17 | "type": "string", 18 | "title": "Admin email", 19 | "form": true 20 | }, 21 | "ghostBlogTitle": { 22 | "type": "string", 23 | "title": "Blog Name", 24 | "form": true 25 | }, 26 | "ghostHost": { 27 | "type": "string", 28 | "title": "Host", 29 | "form": true, 30 | "description": "Hostname used to generate application URLs" 31 | }, 32 | "persistence": { 33 | "type": "object", 34 | "properties": { 35 | "size": { 36 | "type": "string", 37 | "title": "Persistent Volume Size", 38 | "form": true, 39 | "render": "slider", 40 | "sliderMin": 1, 41 | "sliderMax": 100, 42 | "sliderUnit": "Gi" 43 | } 44 | } 45 | }, 46 | "mariadb": { 47 | "type": "object", 48 | "form": true, 49 | "title": "MariaDB Details", 50 | "properties": { 51 | "enabled": { 52 | "type": "boolean", 53 | "title": "Use a new MariaDB database hosted in the cluster", 54 | "form": true, 55 | "description": "Whether to deploy a mariadb server to satisfy the applications database requirements. To use an external database switch this off and configure the external database parameters" 56 | }, 57 | "master": { 58 | "type": "object", 59 | "properties": { 60 | "persistence": { 61 | "type": "object", 62 | "properties": { 63 | "size": { 64 | "type": "string", 65 | "title": "Volume Size", 66 | "form": true, 67 | "hidden": { 68 | "condition": false, 69 | "value": "mariadb.enabled" 70 | }, 71 | "render": "slider", 72 | "sliderMin": 1, 73 | "sliderMax": 100, 74 | "sliderUnit": "Gi" 75 | } 76 | } 77 | } 78 | } 79 | } 80 | } 81 | }, 82 | "externalDatabase": { 83 | "type": "object", 84 | "title": "External Database Details", 85 | "description": "If MariaDB is disabled. Use this section to specify the external database details", 86 | "form": true, 87 | "properties": { 88 | "host": { 89 | "type": "string", 90 | "form": true, 91 | "title": "Database Host", 92 | "hidden": "mariadb.enabled" 93 | }, 94 | "user": { 95 | "type": "string", 96 | "form": true, 97 | "title": "Database Username", 98 | "hidden": "mariadb.enabled" 99 | }, 100 | "password": { 101 | "type": "string", 102 | "form": true, 103 | "title": "Database Password", 104 | "hidden": "mariadb.enabled" 105 | }, 106 | "database": { 107 | "type": "string", 108 | "form": true, 109 | "title": "Database Name", 110 | "hidden": "mariadb.enabled" 111 | }, 112 | "port": { 113 | "type": "integer", 114 | "form": true, 115 | "title": "Database Port", 116 | "hidden": "mariadb.enabled" 117 | } 118 | } 119 | }, 120 | "resources": { 121 | "type": "object", 122 | "title": "Required Resources", 123 | "description": "Configure resource requests", 124 | "form": true, 125 | "properties": { 126 | "requests": { 127 | "type": "object", 128 | "properties": { 129 | "memory": { 130 | "type": "string", 131 | "form": true, 132 | "render": "slider", 133 | "title": "Memory Request", 134 | "sliderMin": 10, 135 | "sliderMax": 2048, 136 | "sliderUnit": "Mi" 137 | }, 138 | "cpu": { 139 | "type": "string", 140 | "form": true, 141 | "render": "slider", 142 | "title": "CPU Request", 143 | "sliderMin": 10, 144 | "sliderMax": 2000, 145 | "sliderUnit": "m" 146 | } 147 | } 148 | } 149 | } 150 | }, 151 | "securityContext": { 152 | "type": "object", 153 | "properties": { 154 | "enabled": { 155 | "type": "boolean", 156 | "title": "Enable Pod Security Context", 157 | "description": "When disabled, an initContainer will be used to set required folder permissions", 158 | "form": true 159 | } 160 | } 161 | } 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /charts/ghost/values.yaml: -------------------------------------------------------------------------------- 1 | ## Global Docker image parameters 2 | ## Please, note that this will override the image parameters, including dependencies, configured to use the global value 3 | ## Current available global Docker image parameters: imageRegistry and imagePullSecrets 4 | ## 5 | # global: 6 | # imageRegistry: myRegistryName 7 | # imagePullSecrets: 8 | # - myRegistryKeySecretName 9 | # storageClass: myStorageClass 10 | 11 | ## Bitnami Ghost image version 12 | ## ref: https://hub.docker.com/r/bitnami/ghost/tags/ 13 | ## 14 | image: 15 | registry: docker.io 16 | repository: bitnami/ghost 17 | tag: 3.1.1-debian-9-r0 18 | ## Specify a imagePullPolicy 19 | ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' 20 | ## ref: http://kubernetes.io/docs/user-guide/images/#pre-pulling-images 21 | ## 22 | pullPolicy: IfNotPresent 23 | ## Optionally specify an array of imagePullSecrets. 24 | ## Secrets must be manually created in the namespace. 25 | ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ 26 | ## 27 | # pullSecrets: 28 | # - myRegistryKeySecretName 29 | 30 | ## String to partially override ghost.fullname template (will maintain the release name) 31 | ## 32 | # nameOverride: 33 | 34 | ## String to fully override ghost.fullname template 35 | ## 36 | # fullnameOverride: 37 | 38 | ## Init containers parameters: 39 | ## volumePermissions: Change the owner of the persist volume mountpoint to RunAsUser:fsGroup 40 | ## 41 | volumePermissions: 42 | image: 43 | registry: docker.io 44 | repository: bitnami/minideb 45 | tag: stretch 46 | pullPolicy: Always 47 | ## Optionally specify an array of imagePullSecrets. 48 | ## Secrets must be manually created in the namespace. 49 | ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ 50 | ## 51 | # pullSecrets: 52 | # - myRegistryKeySecretName 53 | 54 | ## Ghost protocol, host, port and path to create application URLs 55 | ## ref: https://github.com/bitnami/bitnami-docker-ghost#configuration 56 | ## 57 | ghostProtocol: http 58 | # ghostHost: 59 | # ghostPort: 60 | ghostPath: / 61 | 62 | ## User of the application 63 | ## ref: https://github.com/bitnami/bitnami-docker-ghost#configuration 64 | ## 65 | ghostUsername: user@example.com 66 | 67 | ## Application password 68 | ## Defaults to a random 10-character alphanumeric string if not set 69 | ## ref: https://github.com/bitnami/bitnami-docker-ghost#configuration 70 | ## 71 | # ghostPassword: 72 | 73 | ## Admin email 74 | ## ref: https://github.com/bitnami/bitnami-docker-ghost#configuration 75 | ## 76 | ghostEmail: user@example.com 77 | 78 | ## Ghost Blog name 79 | ## ref: https://github.com/bitnami/bitnami-docker-ghost#environment-variables 80 | ## 81 | ghostBlogTitle: User's Blog 82 | 83 | ## Set to `yes` to allow the container to be started with blank passwords 84 | ## ref: https://github.com/bitnami/bitnami-docker-wordpress#environment-variables 85 | allowEmptyPassword: "yes" 86 | 87 | ## SMTP mail delivery configuration 88 | ## ref: https://github.com/bitnami/bitnami-docker-redmine/#smtp-configuration 89 | ## 90 | # smtpHost: 91 | # smtpPort: 92 | # smtpUser: 93 | # smtpPassword: 94 | # smtpFromAddress 95 | # smtpService: 96 | 97 | ## 98 | ## External database configuration 99 | ## 100 | externalDatabase: 101 | ## All of these values are only used when mariadb.enabled is set to false 102 | ## Database host 103 | host: localhost 104 | 105 | ## non-root Username for Wordpress Database 106 | user: bn_ghost 107 | 108 | ## Database password 109 | password: "" 110 | 111 | ## Database name 112 | database: bitnami_ghost 113 | 114 | ## Database port number 115 | port: 3306 116 | 117 | ## 118 | ## MariaDB chart configuration 119 | ## 120 | ## https://github.com/helm/charts/blob/master/stable/mariadb/values.yaml 121 | ## 122 | mariadb: 123 | ## Whether to deploy a mariadb server to satisfy the applications database requirements. To use an external database set this to false and configure the externalDatabase parameters 124 | enabled: true 125 | ## Disable MariaDB replication 126 | replication: 127 | enabled: false 128 | 129 | ## Create a database and a database user 130 | ## ref: https://github.com/bitnami/bitnami-docker-mariadb/blob/master/README.md#creating-a-database-user-on-first-run 131 | ## 132 | db: 133 | name: bitnami_ghost 134 | user: bn_ghost 135 | ## If the password is not specified, mariadb will generates a random password 136 | ## 137 | # password: 138 | 139 | ## MariaDB admin password 140 | ## ref: https://github.com/bitnami/bitnami-docker-mariadb/blob/master/README.md#setting-the-root-password-on-first-run 141 | ## 142 | # rootUser: 143 | # password: 144 | 145 | ## Enable persistence using Persistent Volume Claims 146 | ## ref: http://kubernetes.io/docs/user-guide/persistent-volumes/ 147 | ## 148 | master: 149 | persistence: 150 | enabled: true 151 | ## mariadb data Persistent Volume Storage Class 152 | ## If defined, storageClassName: 153 | ## If set to "-", storageClassName: "", which disables dynamic provisioning 154 | ## If undefined (the default) or set to null, no storageClassName spec is 155 | ## set, choosing the default provisioner. (gp2 on AWS, standard on 156 | ## GKE, AWS & OpenStack) 157 | ## 158 | # storageClass: "-" 159 | accessMode: ReadWriteOnce 160 | size: 8Gi 161 | 162 | ## Kubernetes configuration 163 | ## For minikube, set this to NodePort, elsewhere use LoadBalancer 164 | ## 165 | service: 166 | type: LoadBalancer 167 | # HTTP Port 168 | port: 80 169 | ## loadBalancerIP: 170 | ## 171 | ## nodePorts: 172 | ## http: 173 | nodePorts: 174 | http: "" 175 | ## Enable client source IP preservation 176 | ## ref http://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip 177 | ## 178 | externalTrafficPolicy: Cluster 179 | ## Service annotations done as key:value pairs 180 | annotations: 181 | 182 | ## Pod Security Context 183 | ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ 184 | ## 185 | securityContext: 186 | enabled: true 187 | fsGroup: 1001 188 | runAsUser: 1001 189 | 190 | ## Enable persistence using Persistent Volume Claims 191 | ## ref: http://kubernetes.io/docs/user-guide/persistent-volumes/ 192 | ## 193 | persistence: 194 | enabled: true 195 | ## ghost data Persistent Volume Storage Class 196 | ## If defined, storageClassName: 197 | ## If set to "-", storageClassName: "", which disables dynamic provisioning 198 | ## If undefined (the default) or set to null, no storageClassName spec is 199 | ## set, choosing the default provisioner. (gp2 on AWS, standard on 200 | ## GKE, AWS & OpenStack) 201 | ## 202 | # storageClass: "-" 203 | accessMode: ReadWriteOnce 204 | size: 8Gi 205 | path: /bitnami 206 | 207 | ## Configure resource requests and limits 208 | ## ref: http://kubernetes.io/docs/user-guide/compute-resources/ 209 | ## 210 | resources: 211 | requests: 212 | memory: 512Mi 213 | cpu: 300m 214 | 215 | ## Configure the ingress resource that allows you to access the 216 | ## Ghost installation. Set up the URL 217 | ## ref: http://kubernetes.io/docs/user-guide/ingress/ 218 | ## 219 | ingress: 220 | ## Set to true to enable ingress record generation 221 | enabled: false 222 | 223 | ## Set this to true in order to add the corresponding annotations for cert-manager 224 | certManager: false 225 | 226 | ## Ingress annotations done as key:value pairs 227 | ## For a full list of possible ingress annotations, please see 228 | ## ref: https://github.com/kubernetes/ingress-nginx/blob/master/docs/user-guide/nginx-configuration/annotations.md 229 | ## 230 | ## If tls is set to true, annotation ingress.kubernetes.io/secure-backends: "true" will automatically be set 231 | ## If certManager is set to true, annotation kubernetes.io/tls-acme: "true" will automatically be set 232 | annotations: 233 | # kubernetes.io/ingress.class: nginx 234 | 235 | ## The list of hostnames to be covered with this ingress record. 236 | ## Most likely this will be just one host, but in the event more hosts are needed, this is an array 237 | hosts: 238 | - name: ghost.local 239 | path: / 240 | 241 | ## Set this to true in order to enable TLS on the ingress record 242 | tls: false 243 | 244 | ## Optionally specify the TLS hosts for the ingress record 245 | ## Useful when the Ingress controller supports www-redirection 246 | ## If not specified, the above host name will be used 247 | # tlsHosts: 248 | # - www.ghost.local 249 | # - ghost.local 250 | 251 | ## If TLS is set to true, you must declare what secret will store the key/certificate for TLS 252 | tlsSecret: ghost.local-tls 253 | 254 | secrets: 255 | ## If you're providing your own certificates, please use this to add the certificates as secrets 256 | ## key and certificate should start with -----BEGIN CERTIFICATE----- or 257 | ## -----BEGIN RSA PRIVATE KEY----- 258 | ## 259 | ## name should line up with a tlsSecret set further up 260 | ## If you're using cert-manager, this is unneeded, as it will create the secret for you if it is not set 261 | ## 262 | ## It is also possible to create and manage the certificates outside of this helm chart 263 | ## Please see README.md for more information 264 | # - name: ghost.local-tls 265 | # key: 266 | # certificate: 267 | 268 | ## Node selector for pod assignment 269 | ## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector 270 | ## 271 | nodeSelector: {} 272 | 273 | ## Affinity for pod assignment 274 | ## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity 275 | ## 276 | affinity: {} 277 | -------------------------------------------------------------------------------- /namespaces/demo.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | labels: 5 | name: demo 6 | name: demo 7 | -------------------------------------------------------------------------------- /releases/ghost.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: helm.fluxcd.io/v1 3 | kind: HelmRelease 4 | metadata: 5 | name: ghost 6 | namespace: demo 7 | annotations: 8 | fluxcd.io/automated: "false" 9 | fluxcd.io/tag.chart-image: glob:3.1.1-debian-9-* 10 | spec: 11 | releaseName: ghost 12 | chart: 13 | git: ssh://git@github.com/fluxcd/flux-get-started 14 | ref: master 15 | path: charts/ghost 16 | values: 17 | image: 18 | repository: bitnami/ghost 19 | tag: 3.1.1-debian-9-r0 20 | persistence: 21 | enabled: false 22 | resources: 23 | requests: 24 | memory: 32Mi 25 | cpu: 10m 26 | service: 27 | type: ClusterIP 28 | mariadb: 29 | master: 30 | persistence: 31 | enabled: false 32 | -------------------------------------------------------------------------------- /releases/mongodb.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: helm.fluxcd.io/v1 3 | kind: HelmRelease 4 | metadata: 5 | name: mongodb 6 | namespace: demo 7 | annotations: 8 | fluxcd.io/automated: "false" 9 | fluxcd.io/tag.chart-image: semver:~4.0 10 | spec: 11 | releaseName: mongodb 12 | chart: 13 | repository: https://kubernetes-charts.storage.googleapis.com/ 14 | name: mongodb 15 | version: 7.6.3 16 | values: 17 | image: 18 | repository: bitnami/mongodb 19 | tag: 4.0.13 20 | usePassword: false 21 | persistence: 22 | enabled: false 23 | securityContext: 24 | enabled: true 25 | fsGroup: 0 26 | runAsUser: 0 27 | -------------------------------------------------------------------------------- /releases/redis-auth.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # This secret should be stored in Git encrypted 3 | # Sealed Secrets example: https://github.com/stefanprodan/gitops-helm#managing-kubernetes-secrets 4 | apiVersion: v1 5 | kind: Secret 6 | metadata: 7 | name: redis-auth 8 | namespace: demo 9 | data: 10 | values.yaml: cGFzc3dvcmQ6IGFkbWlu 11 | -------------------------------------------------------------------------------- /releases/redis.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: helm.fluxcd.io/v1 3 | kind: HelmRelease 4 | metadata: 5 | name: redis 6 | namespace: demo 7 | annotations: 8 | fluxcd.io/automated: "true" 9 | fluxcd.io/tag.chart-image: semver:~5.0 10 | fluxcd.io/locked: "true" 11 | fluxcd.io/locked_msg: "Halt updates for now" 12 | fluxcd.io/locked_user: "Stefan Prodan " 13 | spec: 14 | releaseName: redis 15 | chart: 16 | repository: https://kubernetes-charts.storage.googleapis.com/ 17 | name: redis 18 | version: 10.3.1 19 | valueFileSecrets: 20 | # the redis-auth secret contains the password value 21 | - name: redis-auth 22 | values: 23 | usePassword: true 24 | image: 25 | repository: bitnami/redis 26 | tag: 5.0.7 27 | service: 28 | type: ClusterIP 29 | port: 6379 30 | cluster: 31 | enabled: false 32 | master: 33 | securityContext: 34 | enabled: false 35 | fsGroup: 0 36 | runAsUser: 0 37 | persistence: 38 | enabled: false 39 | -------------------------------------------------------------------------------- /workloads/podinfo-dep.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: podinfo 6 | namespace: demo 7 | labels: 8 | app: podinfo 9 | annotations: 10 | fluxcd.io/automated: "true" 11 | fluxcd.io/tag.init: regex:^3.10.* 12 | fluxcd.io/tag.podinfod: semver:~3.1 13 | spec: 14 | strategy: 15 | rollingUpdate: 16 | maxUnavailable: 0 17 | type: RollingUpdate 18 | selector: 19 | matchLabels: 20 | app: podinfo 21 | template: 22 | metadata: 23 | annotations: 24 | prometheus.io/scrape: "true" 25 | prometheus.io/port: "9797" 26 | labels: 27 | app: podinfo 28 | spec: 29 | initContainers: 30 | - name: init 31 | image: alpine:3.10.1 32 | command: 33 | - sleep 34 | - "1" 35 | containers: 36 | - name: podinfod 37 | image: stefanprodan/podinfo:3.1.0 38 | imagePullPolicy: IfNotPresent 39 | ports: 40 | - name: http 41 | containerPort: 9898 42 | protocol: TCP 43 | - name: http-metrics 44 | containerPort: 9797 45 | protocol: TCP 46 | - name: grpc 47 | containerPort: 9999 48 | protocol: TCP 49 | command: 50 | - ./podinfo 51 | - --port=9898 52 | - --port-metrics=9797 53 | - --grpc-port=9999 54 | - --grpc-service-name=podinfo 55 | - --level=info 56 | - --random-delay=false 57 | - --random-error=false 58 | env: 59 | - name: PODINFO_UI_COLOR 60 | value: "#34577c" 61 | livenessProbe: 62 | httpGet: 63 | path: /healthz 64 | port: 9898 65 | readinessProbe: 66 | httpGet: 67 | path: /readyz 68 | port: 9898 69 | resources: 70 | limits: 71 | cpu: 1000m 72 | memory: 128Mi 73 | requests: 74 | cpu: 10m 75 | memory: 64Mi 76 | -------------------------------------------------------------------------------- /workloads/podinfo-hpa.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: autoscaling/v2beta1 2 | kind: HorizontalPodAutoscaler 3 | metadata: 4 | name: podinfo 5 | namespace: demo 6 | spec: 7 | scaleTargetRef: 8 | apiVersion: apps/v1 9 | kind: Deployment 10 | name: podinfo 11 | minReplicas: 2 12 | maxReplicas: 4 13 | metrics: 14 | - type: Resource 15 | resource: 16 | name: cpu 17 | # scale up if usage is above 18 | # 99% of the requested CPU (10m) 19 | targetAverageUtilization: 99 20 | -------------------------------------------------------------------------------- /workloads/podinfo-svc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: podinfo 5 | namespace: demo 6 | labels: 7 | app: podinfo 8 | spec: 9 | type: ClusterIP 10 | selector: 11 | app: podinfo 12 | ports: 13 | - name: http 14 | port: 9898 15 | protocol: TCP 16 | targetPort: http 17 | --------------------------------------------------------------------------------