• Stars
    star
    1,309
  • Rank 34,443 (Top 0.7 %)
  • Language
    Ruby
  • License
    MIT License
  • Created over 7 years ago
  • Updated 11 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A command-line tool that helps you ship changes to a Kubernetes namespace and understand the result

krane Build status

This project used to be called kubernetes-deploy. Check out our migration guide for more information including details about breaking changes.

krane is a command line tool that helps you ship changes to a Kubernetes namespace and understand the result. At Shopify, we use it within our much-beloved, open-source Shipit deployment app.

Why not just use the standard kubectl apply mechanism to deploy? It is indeed a fantastic tool; krane uses it under the hood! However, it leaves its users with some burning questions: What just happened? Did it work?

Especially in a CI/CD environment, we need a clear, actionable pass/fail result for each deploy. Providing this was the foundational goal of krane, which has grown to support the following core features:

👀 Watches the changes you requested to make sure they roll out successfully.

⁉️ Provides debug information for changes that failed.

🔢 Predeploys certain types of resources (e.g. ConfigMap, PersistentVolumeClaim) to make sure the latest version will be available when resources that might consume them (e.g. Deployment) are deployed.

🔐 Creates Kubernetes secrets from encrypted EJSON, which you can safely commit to your repository

🏃 Running tasks at the beginning of a deploy using bare pods (example use case: Rails migrations)

If you need the ability to render dynamic values in templates before deploying, you can use krane render. Alongside that, this repo also includes tools for running tasks and restarting deployments.

demo-deploy.gif

missing-secret-fail


Table of contents

KRANE DEPLOY

KRANE GLOBAL DEPLOY

KRANE RESTART

KRANE RUN

KRANE RENDER

CONTRIBUTING


Prerequisites

  • Ruby 2.7+
  • Your cluster must be running Kubernetes v1.22.0 or higher1

Compatibility

1 We run integration tests against these Kubernetes versions. You can find our official compatibility chart below.

Krane provides support for official upstream supported versions Kubernetes, Ruby that are part of the compatibility matrix; Nevertheless, older releases are still likely to work.

Kubernetes version Currently Tested? Last officially supported in gem version
1.18 No 2.3.7
1.19 No 2.4.9
1.20 No 2.4.9
1.21 No 2.4.9
1.22 No 3.0.1
1.23 Yes --
1.24 Yes --
1.25 No --
1.26 Yes --

Installation

  1. Install kubectl (requires v1.22.0 or higher) and make sure it is available in your $PATH
  2. Set up your kubeconfig file for access to your cluster(s).
  3. gem install krane

Usage

krane deploy <app's namespace> <kube context>

Environment variables:

  • $KUBECONFIG: points to one or multiple valid kubeconfig files that include the context you want to deploy to. File names are separated by colon for Linux and Mac, and semi-colon for Windows. If omitted, Krane will use the Kubernetes default of ~/.kube/config.
  • $GOOGLE_APPLICATION_CREDENTIALS: points to the credentials for an authenticated service account (required if your kubeconfig user's auth provider is GCP)

Options:

Refer to krane help for the authoritative set of options.

  • --filenames / -f [PATHS]: Accepts a list of directories and/or filenames to specify the set of directories/files that will be deployed, use - to specify reading from STDIN.
  • --no-prune: Skips pruning of resources that are no longer in your Kubernetes template set. Not recommended, as it allows your namespace to accumulate cruft that is not reflected in your deploy directory.
  • --global-timeout=duration: Raise a timeout error if it takes longer than duration for any resource to deploy.
  • --selector: Instructs krane to only prune resources which match the specified label selector, such as environment=staging. If you use this option, all resource templates must specify matching labels. See Sharing a namespace below.
  • --selector-as-filter: Instructs krane to only deploy resources that are filtered by the specified labels in --selector. The deploy will not fail if not all resources match the labels. This is useful if you only want to deploy a subset of resources within a given YAML file. See Sharing a namespace below.
  • --no-verify-result: Skip verification that workloads correctly deployed.
  • --protected-namespaces=default kube-system kube-public: Fail validation if a deploy is targeted at a protected namespace.
  • --verbose-log-prefix: Add [context][namespace] to the log prefix

NOTICE: Deploy Secret resources at your own risk. Although we will fix any reported leak vectors with urgency, we cannot guarantee that sensitive information will never be logged.

Sharing a namespace

By default, krane will prune any resources in the target namespace which have the kubectl.kubernetes.io/last-applied-configuration annotation and are not a result of the current deployment process, on the assumption that there is a one-to-one relationship between application deployment and namespace, and that a deployment provisions all relevant resources in the namespace.

If you need to, you may specify --no-prune to disable all pruning behaviour, but this is not recommended.

If you need to share a namespace with resources which are managed by other tools or indeed other krane deployments, you can supply the --selector option, such that only resources with labels matching the selector are considered for pruning.

If you need to share a namespace with different set of resources using the same YAML file, you can supply the --selector and --selector-as-filter options, such that only the resources that match with the labels will be deployed. In each run of deploy, you can use different labels in --selector to deploy a different set of resources. Only the deployed resources in each run are considered for pruning.

Using templates

All templates must be YAML formatted. We recommended storing each app's templates in a single directory, {app root}/config/deploy/{env}. However, you may use multiple directories.

If you want dynamic templates, you may render ERB with krane render and then pipe that result to krane deploy -f -.

Customizing behaviour with annotations

  • krane.shopify.io/timeout-override: Override the tool's hard timeout for one specific resource. Both full ISO8601 durations and the time portion of ISO8601 durations are valid. Value must be between 1 second and 24 hours.
    • Example values: 45s / 3m / 1h / PT0.25H
    • Compatibility: all resource types
  • krane.shopify.io/required-rollout: Modifies how much of the rollout needs to finish before the deployment is considered successful.
    • Compatibility: Deployment
    • full: The deployment is successful when all pods in the new replicaSet are ready.
    • none: The deployment is successful as soon as the new replicaSet is created for the deployment.
    • maxUnavailable: The deploy is successful when minimum availability is reached in the new replicaSet. In other words, the number of new pods that must be ready is equal to spec.replicas - strategy.RollingUpdate.maxUnavailable (converted from percentages by rounding up, if applicable). This option is only valid for deployments that use the RollingUpdate strategy.
    • Percent (e.g. 90%): The deploy is successful when the number of new pods that are ready is equal to spec.replicas * Percent.
  • krane.shopify.io/predeployed: Causes a Custom Resource to be deployed in the pre-deploy phase.
    • Compatibility: Custom Resource Definition
    • Default: true
    • true: The custom resource will be deployed in the pre-deploy phase.
    • All other values: The custom resource will be deployed in the main deployment phase.
  • krane.shopify.io/deploy-method-override: Cause a resource to be deployed by the specified kubectl command, instead of the default apply.
    • Compatibility: Cannot be used for PodDisruptionBudget, since it always uses create/replace-force
    • Accepted values: create, replace, and replace-force
    • Warning: Resources whose deploy method is overridden are no longer subject to pruning on deploy.
    • This feature is experimental and may be removed at any time.

Running tasks at the beginning of a deploy

To run a task in your cluster at the beginning of every deploy, simply include a Pod template in your deploy directory. krane will first deploy any ConfigMap and PersistentVolumeClaim resources present in the provided templates, followed by any such pods. If the command run by one of these pods fails (i.e. exits with a non-zero status), the overall deploy will fail at this step (no other resources will be deployed).

Requirements:

  • The pod's name should include <%= deployment_id %> to ensure that a unique name will be used on every deploy (the deploy will fail if a pod with the same name already exists).
  • The pod's spec.restartPolicy must be set to Never so that it will be run exactly once. We'll fail the deploy if that run exits with a non-zero status.
  • The pod's spec.activeDeadlineSeconds should be set to a reasonable value for the performed task (not required, but highly recommended)

A simple example can be found in the test fixtures: test/fixtures/hello-cloud/unmanaged-pod-1.yml.erb.

The logs of all pods run in this way will be printed inline. If there is only one pod, the logs will be streamed in real-time. If there are multiple, they will be fetched when the pod terminates.

migrate-logs

Deploying Kubernetes secrets (from EJSON)

Note: If you're a Shopify employee using our cloud platform, this setup has already been done for you. Please consult the CloudPlatform User Guide for usage instructions.

Since their data is only base64 encoded, Kubernetes secrets should not be committed to your repository. Instead, krane supports generating secrets from an encrypted ejson file in your template directory. Here's how to use this feature:

  1. Install the ejson gem: gem install ejson
  2. Generate a new keypair: ejson keygen (prints the keypair to stdout)
  3. Create a Kubernetes secret in your target namespace with the new keypair: kubectl create secret generic ejson-keys --from-literal=YOUR_PUBLIC_KEY=YOUR_PRIVATE_KEY --namespace=TARGET_NAMESPACE

Warning: Do not use apply to create the ejson-keys secret. krane will fail if ejson-keys is prunable. This safeguard is to protect against the accidental deletion of your private keys.

  1. (optional but highly recommended) Back up the keypair somewhere secure, such as a password manager, for disaster recovery purposes.
  2. In your template directory (alongside your Kubernetes templates), create secrets.ejson with the format shown below. The _type key should have the value “kubernetes.io/tls” for TLS secrets and “Opaque” for all others. The data key must be a json object, but its keys and values can be whatever you need.
{
  "_public_key": "YOUR_PUBLIC_KEY",
  "kubernetes_secrets": {
    "catphotoscom": {
      "_type": "kubernetes.io/tls",
      "data": {
        "tls.crt": "cert-data-here",
        "tls.key": "key-data-here"
      }
    },
    "monitoring-token": {
      "_type": "Opaque",
      "data": {
        "api-token": "token-value-here"
      }
    }
  }
}
  1. Encrypt the file: ejson encrypt /PATH/TO/secrets.ejson
  2. Commit the encrypted file and deploy. The deploy will create secrets from the data in the kubernetes_secrets key. The ejson file must be included in the resources passed to --filenames it can not be read through stdin.

Note: Since leading underscores in ejson keys are used to skip encryption of the associated value, krane will strip these leading underscores when it creates the keys for the Kubernetes secret data. For example, given the ejson data below, the monitoring-token secret will have keys api-token and property (not _property):

{
  "_public_key": "YOUR_PUBLIC_KEY",
  "kubernetes_secrets": {
    "monitoring-token": {
      "_type": "kubernetes.io/tls",
      "data": {
        "api-token": "EJ[ENCRYPTED]",
        "_property": "some unencrypted value"
      }
    }
  }

A warning about using EJSON secrets with --selector: when using EJSON to generate Secret resources and specifying a --selector for deployment, the labels from the selector are automatically added to the Secret. If the same EJSON file is deployed to the same namespace using different selectors, this will cause the resource to thrash - even if the contents of the secret were the same, the resource has different labels on each deploy.

Deploying custom resources

By default, krane does not check the status of custom resources; it simply assumes that they deployed successfully. In order to meaningfully monitor the rollout of custom resources, krane supports configuring pass/fail conditions using annotations on CustomResourceDefinitions (CRDs).

Requirements:

  • The custom resource must expose a status subresource with an observedGeneration field.
  • The krane.shopify.io/instance-rollout-conditions annotation must be present on the CRD that defines the custom resource.
  • (optional) The krane.shopify.io/instance-timeout annotation can be added to the CRD that defines the custom resource to override the global default timeout for all instances of that resource. This annotation can use ISO8601 format or unprefixed ISO8601 time components (e.g. '1H', '60S').

Specifying pass/fail conditions

The presence of a valid krane.shopify.io/instance-rollout-conditions annotation on a CRD will cause krane to monitor the rollout of all instances of that custom resource. Its value can either be "true" (giving you the defaults described in the next section) or a valid JSON string with the following format:

'{
  "success_conditions": [
    { "path": <JsonPath expression>, "value": <target value> }
    ... more success conditions
  ],
  "failure_conditions": [
    { "path": <JsonPath expression>, "value": <target value> }
    ... more failure conditions
  ]
}'

For all conditions, path must be a valid JsonPath expression that points to a field in the custom resource's status. value is the value that must be present at path in order to fulfill a condition. For a deployment to be successful, all success_conditions must be fulfilled. Conversely, the deploy will be marked as failed if any one of failure_conditions is fulfilled. success_conditions are mandatory, but failure_conditions can be omitted (the resource will simply time out if it never reaches a successful state).

In addition to path and value, a failure condition can also contain error_msg_path or custom_error_msg. error_msg_path is a JsonPath expression that points to a field you want to surface when a failure condition is fulfilled. For example, a status condition may expose a message field that contains a description of the problem it encountered. custom_error_msg is a string that can be used if your custom resource doesn't contain sufficient information to warrant using error_msg_path. Note that custom_error_msg has higher precedence than error_msg_path so it will be used in favor of error_msg_path when both fields are present.

Warning:

You must ensure that your custom resource controller sets .status.observedGeneration to match the observed .metadata.generation of the monitored resource once its sync is complete. If this does not happen, krane will not check success or failure conditions and the deploy will time out.

Example

As an example, the following is the default configuration that will be used if you set krane.shopify.io/instance-rollout-conditions: "true" on the CRD that defines the custom resources you wish to monitor:

'{
  "success_conditions": [
    {
      "path": "$.status.conditions[?(@.type == \"Ready\")].status",
      "value": "True",
    },
  ],
  "failure_conditions": [
    {
      "path": '$.status.conditions[?(@.type == \"Failed\")].status',
      "value": "True",
      "error_msg_path": '$.status.conditions[?(@.type == \"Failed\")].message',
    },
  ],
}'

The paths defined here are based on the typical status properties as defined by the Kubernetes community. It expects the status subresource to contain a conditions array whose entries minimally specify type, status, and message fields.

You can see how these conditions relate to the following resource:

apiVersion: stable.shopify.io/v1
kind: Example
metadata:
  generation: 2
  name: example
  namespace: namespace
spec:
  ...
status:
  observedGeneration: 2
  conditions:
  - type: "Ready"
    status: "False"
    reason: "exampleNotReady"
    message: "resource is not ready"
  - type: "Failed"
    status: "True"
    reason: "exampleFailed"
    message: "resource is failed"
  • observedGeneration == metadata.generation, so krane will check this resource's success and failure conditions.
  • Since $.status.conditions[?(@.type == "Ready")].status == "False", the resource is not considered successful yet.
  • $.status.conditions[?(@.type == "Failed")].status == "True" means that a failure condition has been fulfilled and the resource is considered failed.
  • Since error_msg_path is specified, krane will log the contents of $.status.conditions[?(@.type == "Failed")].message, which in this case is: resource is failed.

Deploy walkthrough

Let's walk through what happens when you run the deploy task with this directory of templates. This particular example uses ERB templates as well, so we'll use the krane render task to achieve that.

You can test this out for yourself by running the following command:

krane render -f test/fixtures/hello-cloud --current-sha 1 | krane deploy my-namespace my-k8s-cluster -f -

As soon as you run this, you'll start seeing some output being streamed to STDERR.

Phase 1: Initializing deploy

In this phase, we:

  • Perform basic validation to ensure we can proceed with the deploy. This includes checking if we can reach the context, if the context is valid, if the namespace exists within the context, and more. We try to validate as much as we can before trying to ship something because we want to avoid having an incomplete deploy in case of a failure (this is especially important because there's no rollback support).
  • List out all the resources we want to deploy (as described in the template files we used).

Phase 2: Checking initial resource statuses

In this phase, we check resource statuses. For each resource listed in the previous step, we check Kubernetes for their status; in the first deploy this might show a bunch of items as "Not Found", but for the deploy of a new version, this is an example of what it could look like:

Certificate/services-foo-tls     Exists
Cloudsql/foo-production          Provisioned
Deployment/jobs                  3 replicas, 3 updatedReplicas, 3 availableReplicas
Deployment/web                   3 replicas, 3 updatedReplicas, 3 availableReplicas
Ingress/web                      Created
Memcached/foo-production         Healthy
Pod/db-migrate-856359            Unknown
Pod/upload-assets-856359         Unknown
Redis/foo-production             Healthy
Service/web                      Selects at least 1 pod

The next phase might be either "Predeploying priority resources" (if there's any) or "Deploying all resources". In this example we'll go through the former, as we do have predeployable resources.

Phase 3: Predeploying priority resources

This is the first phase that could modify the cluster.

In this phase we predeploy certain types of resources (e.g. ConfigMap, PersistentVolumeClaim, Secret, ...) to make sure the latest version will be available when resources that might consume them (e.g. Deployment) are deployed. This phase will be skipped if the templates don't include any resources that would need to be predeployed.

When this runs, we essentially run kubectl apply on those templates and periodically check the cluster for the current status of each resource so we can display error or success information. This will look different depending on the type of resource. If you're running the command described above, you should see something like this in the output:

Deploying ConfigMap/hello-cloud-configmap-data (timeout: 30s)
Successfully deployed in 0.2s: ConfigMap/hello-cloud-configmap-data

Deploying PersistentVolumeClaim/hello-cloud-redis (timeout: 300s)
Successfully deployed in 3.3s: PersistentVolumeClaim/hello-cloud-redis

Deploying Role/role (timeout: 300s)
Don't know how to monitor resources of type Role. Assuming Role/role deployed successfully.
Successfully deployed in 0.2s: Role/role

As you can see, different types of resources might have different timeout values and different success criteria; in some specific cases (such as with Role) we might not know how to confirm success or failure, so we use a higher timeout value and assume it did work.

Phase 4: Deploying all resources

In this phase, we:

  • Deploy all resources found in the templates, including resources that were predeployed in the previous step (which should be treated as a no-op by Kubernetes). We deploy everything so the pruning logic (described below) doesn't remove any predeployed resources.
  • Prune resources not found in the templates (you can disable this by using --no-prune).

Just like in the previous phase, we essentially run kubectl apply on those templates and periodically check the cluster for the current status of each resource so we can display error or success information.

If pruning is enabled (which, again, is the default), any kind not listed in the blacklist that we can find in the namespace but not in the templates will be removed. A particular message about pruning will be printed in the next phase if any resource matches this criteria.

Result

The result section will show:

  • A global status: if all resources were deployed successfully, this will show up as "SUCCESS"; if at least one resource failed to deploy (due to an error or timeout), this will show up as "FAILURE".
  • A list of resources and their individual status: this will show up as something like "Available", "Created", and "1 replica, 1 availableReplica, 1 readyReplica".

At this point the command also returns a status code:

  • If it was a success, 0
  • If there was a timeout, 70
  • If any other failure happened, 1

On timeouts: It's important to notice that a single resource timeout or a global deploy timeout doesn't necessarily mean that the operation failed. Since Kubernetes updates are asynchronous, maybe something was just too slow to return in the configured time; in those cases, usually running the deploy again might work (that should be a no-op for most - if not all - resources).

krane global deploy

Ship non-namespaced resources to a cluster

krane global-deploy (accessible through the Ruby API as Krane::GlobalDeployTask) can deploy global (non-namespaced) resources such as PersistentVolume, Namespace, and CustomResourceDefinition. Its interface is very similar to krane deploy.

Usage

krane global-deploy <kube context>

$ cat my-template.yml
    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: testing-storage-class
      labels:
        app: krane
    provisioner: kubernetes.io/no-provisioner

$ krane global-deploy my-k8s-context -f my-template.yml --selector app=krane

Options:

Refer to krane global-deploy help for the authoritative set of options.

  • --filenames / -f [PATHS]: Accepts a list of directories and/or filenames to specify the set of directories/files that will be deployed. Use - to specify STDIN.
  • --no-prune: Skips pruning of resources that are no longer in your Kubernetes template set. Not recommended, as it allows your namespace to accumulate cruft that is not reflected in your deploy directory.
  • --selector: Instructs krane to only prune resources which match the specified label selector, such as environment=staging. By using this option, all resource templates must specify matching labels. See Sharing a namespace below.
  • --selector-as-filter: Instructs krane to only deploy resources that are filtered by the specified labels in --selector. The deploy will not fail if not all resources match the labels. This is useful if you only want to deploy a subset of resources within a given YAML file. See Sharing a namespace below.
  • --global-timeout=duration: Raise a timeout error if it takes longer than duration for any resource to deploy.
  • --no-verify-result: Skip verification that resources correctly deployed.

krane restart

krane restart is a tool for restarting all of the pods in one or more deployments, statefuls sets, and/or daemon sets. It triggers the restart by patching template metadata with the kubectl.kubernetes.io/restartedAt annotation (with the value being an RFC 3339 representation of the current time). Note this is the manner in which kubectl rollout restart itself triggers restarts.

Usage

Option 1: Specify the deployments you want to restart

The following command will restart all pods in the web and jobs deployments:

krane restart <kube namespace> <kube context> --deployments=web jobs

Option 2: Annotate the deployments you want to restart

Add the annotation shipit.shopify.io/restart to all the deployments you want to target, like this:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
  annotations:
    shipit.shopify.io/restart: "true"

With this done, you can use the following command to restart all of them:

krane restart <kube namespace> <kube context>

Options:

Refer to krane help restart for the authoritative set of options.

  • --selector: Only restarts Deployments which match the specified Kubernetes resource selector.
  • --deployments: Restart specific Deployment resources by name.
  • --global-timeout=duration: Raise a timeout error if it takes longer than duration for any resource to restart.
  • --no-verify-result: Skip verification that workloads correctly restarted.

krane run

krane run is a tool for triggering a one-off job, such as a rake task, outside of a deploy.

Prerequisites

  • You've already deployed a PodTemplate object with field template containing a Pod specification that does not include the apiVersion or kind parameters. An example is provided in this repo in test/fixtures/hello-cloud/template-runner.yml.
  • The Pod specification in that template has a container named task-runner.

Based on this specification krane run will create a new pod with the entrypoint of the task-runner container overridden with the supplied arguments.

Usage

krane run <kube namespace> <kube context> --arguments=<arguments> --command=<command> --template=<template name>

Options:

  • --template=TEMPLATE: Specifies the name of the PodTemplate to use.
  • --env-vars=ENV_VARS: Accepts a list of environment variables to be added to the pod template. For example, --env-vars="ENV=VAL ENV2=VAL2" will make ENV and ENV2 available to the container.
  • --command=: Override the default command in the container image.
  • --no-verify-result: Skip verification of pod success
  • --global-timeout=duration: Raise a timeout error if the pod runs for longer than the specified duration
  • --arguments:: Override the default arguments for the command with a space-separated list of arguments

krane render

krane render is a tool for rendering ERB templates to raw Kubernetes YAML. It's useful for outputting YAML that can be passed to other tools, for validation or introspection purposes.

Prerequisites

  • krane render does not require a running cluster or an active kubernetes context, which is nice if you want to run it in a CI environment, potentially alongside something like https://github.com/garethr/kubeval to make sure your configuration is sound.

Usage

To render all templates in your template dir, run:

krane render -f ./path/to/template/dir

To render some templates in a template dir, run krane render with the names of the templates to render:

krane render -f ./path/to/template/dir/this-template.yaml.erb

To render a template in a template dir and output it to a file, run krane render with the name of the template and redirect the output to a file:

krane render -f ./path/to/template/dir/template.yaml.erb > template.yaml

Options:

  • --filenames / -f [PATHS]: Accepts a list of directories and/or filenames to specify the set of directories/files that will be deployed. Use - to specify STDIN.
  • --bindings=BINDINGS: Makes additional variables available to your ERB templates. For example, krane render --bindings=color=blue size=large -f some-template.yaml.erb will expose color and size to some-template.yaml.erb.
  • --current-sha: Expose SHA current_sha in ERB bindings

You can add additional variables using the --bindings=BINDINGS option which can be formatted as a string, JSON string or path to a JSON or YAML file. Complex JSON or YAML data will be converted to a Hash for use in templates. To load a file, the argument should include the relative file path prefixed with an @ sign. An argument error will be raised if the string argument cannot be parsed, the referenced file does not include a valid extension (.json, .yaml or .yml) or the referenced file does not exist.

Bindings examples

# Comma separated string. Exposes, 'color' and 'size'
$ krane render --bindings=color=blue,size=large

# JSON string. Exposes, 'color' and 'size'
$ krane render --bindings='{"color":"blue","size":"large"}'

# Load JSON file from ./config
$ krane render --bindings='@config/production.json'

# Load YAML file from ./config (.yaml or yml supported)
$ krane render --bindings='@config/production.yaml'

# Load multiple files via a space separated string
$ krane render --bindings='@config/production.yaml' '@config/common.yaml'

Using partials

krane supports composing templates from so called partials in order to reduce duplication in Kubernetes YAML files. Given a directory DIR, partials are searched for in DIR/partialsand in 'DIR/../partials', in that order. They can be embedded in other ERB templates using the helper method partial. For example, let's assume an application needs a number of different CronJob resources, one could place a template called cron in one of those directories and then use it in the main deployment.yaml.erb like so:

<%= partial "cron", name: "cleanup",   schedule: "0 0 * * *", args: %w(cleanup),    cpu: "100m", memory: "100Mi" %>
<%= partial "cron", name: "send-mail", schedule: "0 0 * * *", args: %w(send-mails), cpu: "200m", memory: "256Mi" %>

Inside a partial, parameters can be accessed as normal variables, or via a hash called locals. Thus, the cron template could like this:

---
apiVersion: batch/v1
kind: CronJob
metadata:
  name: cron-<%= name %>
spec:
  schedule: <%= schedule %>
    successfulJobsHistoryLimit: 3
    failedJobsHistoryLimit: 3
    concurrencyPolicy: Forbid
    jobTemplate:
      spec:
        template:
          spec:
            containers:
            - name: cron-<%= name %>
              image: ...
              args: <%= args %>
              resources:
                requests:
                  cpu: "<%= cpu %>"
                  memory: <%= memory %>
            restartPolicy: OnFailure

Both .yaml.erb and .yml.erb file extensions are supported. Templates must refer to the bare filename (e.g. use partial: 'cron' to reference cron.yaml.erb).

Limitations when using partials

Partials can be included almost everywhere in ERB templates. Note: when using a partial to insert additional key-value pairs to a map you must use YAML merge keys. For example, given a partial p defining two fields 'a' and 'b',

a: 1
b: 2

you cannot do this:

x: yz
<%= partial 'p' %>

hoping to get

x: yz
a: 1
b: 2

but you can do:

```yaml
<<: <%= partial 'p' %>
x: yz

This is a limitation of the current implementation.

Contributing

We ❤️ contributors! To make it easier for you and us we've written a Contributing Guide

You can also reach out to us on our slack channel, #krane, at https://kubernetes.slack.com. All are welcome!

Code of Conduct

Everyone is expected to follow our Code of Conduct.

License

The gem is available as open source under the terms of the MIT License.

More Repositories

1

draggable

The JavaScript Drag & Drop library your grandparents warned you about.
JavaScript
17,454
star
2

dashing

The exceptionally handsome dashboard framework in Ruby and Coffeescript.
JavaScript
11,025
star
3

liquid

Liquid markup language. Safe, customer facing template language for flexible web apps.
Ruby
10,419
star
4

toxiproxy

⏰ 🔥 A TCP proxy to simulate network and system conditions for chaos and resiliency testing
Go
9,412
star
5

react-native-skia

High-performance React Native Graphics using Skia
TypeScript
6,392
star
6

polaris

Shopify’s design system to help us work together to build a great experience for all of our merchants.
TypeScript
5,352
star
7

flash-list

A better list for React Native
TypeScript
4,536
star
8

hydrogen-v1

React-based framework for building dynamic, Shopify-powered custom storefronts.
TypeScript
3,760
star
9

go-lua

A Lua VM in Go
Go
2,773
star
10

bootsnap

Boot large Ruby/Rails apps faster
Ruby
2,614
star
11

graphql-design-tutorial

2,335
star
12

restyle

A type-enforced system for building UI components in React Native with TypeScript.
TypeScript
2,331
star
13

dawn

Shopify's first source available reference theme, with Online Store 2.0 features and performance built-in.
Liquid
2,279
star
14

identity_cache

IdentityCache is a blob level caching solution to plug into Active Record. Don't #find, #fetch!
Ruby
1,874
star
15

shopify_app

A Rails Engine for building Shopify Apps
Ruby
1,649
star
16

kubeaudit

kubeaudit helps you audit your Kubernetes clusters against common security controls
Go
1,624
star
17

quilt

A loosely related set of packages for JavaScript/TypeScript projects at Shopify
TypeScript
1,570
star
18

graphql-batch

A query batching executor for the graphql gem
Ruby
1,388
star
19

shipit-engine

Deployment coordination
Ruby
1,382
star
20

packwerk

Good things come in small packages.
Ruby
1,346
star
21

semian

🐒 Resiliency toolkit for Ruby for failing fast
Ruby
1,286
star
22

slate

Slate is a toolkit for developing Shopify themes. It's designed to assist your workflow and speed up the process of developing, testing, and deploying themes.
JavaScript
1,281
star
23

ejson

EJSON is a small library to manage encrypted secrets using asymmetric encryption.
Go
1,246
star
24

superdb

The Super Debugger, a realtime wireless debugger for iOS
Objective-C
1,158
star
25

shopify_python_api

ShopifyAPI library allows Python developers to programmatically access the admin section of stores
Python
1,072
star
26

storefront-api-examples

Example custom storefront applications built on Shopify's Storefront API
JavaScript
1,069
star
27

themekit

Shopify theme development command line tool.
Go
1,068
star
28

Timber

The ultimate Shopify theme framework, built by Shopify.
Liquid
992
star
29

shopify-cli

Shopify CLI helps you build against the Shopify platform faster.
Ruby
987
star
30

shopify-api-ruby

ShopifyAPI is a lightweight gem for accessing the Shopify admin REST and GraphQL web services.
Ruby
982
star
31

hydrogen

Hydrogen is Shopify’s stack for headless commerce. It provides a set of tools, utilities, and best-in-class examples for building dynamic and performant commerce applications. Hydrogen is designed to dovetail with Remix, Shopify’s full stack web framework, but it also provides a React library portable to other supporting frameworks. Demo store 👇🏼
TypeScript
966
star
32

js-buy-sdk

The JS Buy SDK is a lightweight library that allows you to build ecommerce into any website. It is based on Shopify's API and provides the ability to retrieve products and collections from your shop, add products to a cart, and checkout.
JavaScript
932
star
33

job-iteration

Makes your background jobs interruptible and resumable by design.
Ruby
907
star
34

cli-ui

Terminal user interface library
Ruby
869
star
35

ruby-lsp

An opinionated language server for Ruby
Ruby
851
star
36

react-native-performance

Performance monitoring for React Native apps
TypeScript
843
star
37

active_shipping

ActiveShipping is a simple shipping abstraction library extracted from Shopify
Ruby
809
star
38

shopify-api-js

Shopify Admin API Library for Node. Accelerate development with support for authentication, graphql proxy, webhooks
TypeScript
765
star
39

maintenance_tasks

A Rails engine for queueing and managing data migrations.
Ruby
705
star
40

shopify-app-template-node

JavaScript
701
star
41

remote-ui

TypeScript
701
star
42

shopify_theme

A console tool for interacting with Shopify Theme Assets.
Ruby
640
star
43

tapioca

The swiss army knife of RBI generation
Ruby
636
star
44

pitchfork

Ruby
630
star
45

ghostferry

The swiss army knife of live data migrations
Go
596
star
46

yjit

Optimizing JIT compiler built inside CRuby
593
star
47

erb-lint

Lint your ERB or HTML files
Ruby
565
star
48

statsd-instrument

A StatsD client for Ruby apps. Provides metaprogramming methods to inject StatsD instrumentation into your code.
Ruby
546
star
49

shopify.github.com

A collection of the open source projects by Shopify
CSS
505
star
50

theme-scripts

Theme Scripts is a collection of utility libraries which help theme developers with problems unique to Shopify Themes.
JavaScript
470
star
51

livedata-ktx

Kotlin extension for LiveData, chaining like RxJava
Kotlin
467
star
52

starter-theme

The Shopify Themes Team opinionated starting point for new a Slate project
Liquid
459
star
53

ruby-style-guide

Shopify’s Ruby Style Guide
Ruby
446
star
54

shopify-demo-app-node-react

JavaScript
444
star
55

web-configs

Common configurations for building web apps at Shopify
JavaScript
433
star
56

mobile-buy-sdk-ios

Shopify’s Mobile Buy SDK makes it simple to sell physical products inside your mobile app. With a few lines of code, you can connect your app with the Shopify platform and let your users buy your products using Apple Pay or their credit card.
Swift
433
star
57

shopify_django_app

Get a Shopify app up and running with Django and Python Shopify API
Python
425
star
58

deprecation_toolkit

⚒Eliminate deprecations from your codebase ⚒
Ruby
390
star
59

ruby-lsp-rails

A Ruby LSP extension for Rails
Ruby
388
star
60

bootboot

Dualboot your Ruby app made easy
Ruby
374
star
61

FunctionalTableData

Declarative UITableViewDataSource implementation
Swift
365
star
62

shadowenv

reversible directory-local environment variable manipulations
Rust
349
star
63

shopify-node-app

An example app that uses Polaris components and shopify-express
JavaScript
327
star
64

better-html

Better HTML for Rails
Ruby
311
star
65

theme-check

The Ultimate Shopify Theme Linter
Ruby
306
star
66

product-reviews-sample-app

A sample Shopify application that creates and stores product reviews for a store, written in Node.js
JavaScript
300
star
67

tracky

The easiest way to do motion tracking!
Swift
295
star
68

shopify-api-php

PHP
279
star
69

polaris-viz

A collection of React and React native components that compose Shopify's data visualization system
TypeScript
279
star
70

measured

Encapsulate measurements and their units in Ruby.
Ruby
275
star
71

cli

Build apps, themes, and hydrogen storefronts for Shopify
TypeScript
273
star
72

money

Manage money in Shopify with a class that won't lose pennies during division
Ruby
265
star
73

javascript

The home for all things JavaScript at Shopify.
254
star
74

ruvy

Rust
252
star
75

limiter

Simple Ruby rate limiting mechanism.
Ruby
244
star
76

vscode-ruby-lsp

VS Code plugin for connecting with the Ruby LSP
TypeScript
232
star
77

polaris-tokens

Design tokens for Polaris, Shopify’s design system
TypeScript
230
star
78

buy-button-js

BuyButton.js is a highly customizable UI library for adding ecommerce functionality to any website.
JavaScript
230
star
79

android-testify

Add screenshots to your Android tests
Kotlin
225
star
80

turbograft

Hard fork of turbolinks, adding partial page replacement strategies, and utilities.
JavaScript
213
star
81

mobile-buy-sdk-android

Shopify’s Mobile Buy SDK makes it simple to sell physical products inside your mobile app. With a few lines of code, you can connect your app with the Shopify platform and let your users buy your products using their credit card.
Java
202
star
82

spoom

Useful tools for Sorbet enthusiasts
Ruby
192
star
83

graphql-js-client

A Relay compliant GraphQL client.
JavaScript
187
star
84

ruby_memcheck

Use Valgrind memcheck on your native gem without going crazy
Ruby
187
star
85

shopify-app-template-php

PHP
186
star
86

skeleton-theme

A barebones ☠️starter theme with the required files needed to compile with Slate and upload to Shopify.
Liquid
185
star
87

sprockets-commoner

Use Babel in Sprockets to compile JavaScript modules for the browser
Ruby
182
star
88

rotoscope

High-performance logger of Ruby method invocations
Ruby
180
star
89

shopify-app-template-remix

TypeScript
178
star
90

git-chain

Tool to rebase multiple Git branches based on the previous one.
Ruby
176
star
91

verdict

Framework to define and implement A/B tests in your application, and collect data for analysis purposes.
Ruby
176
star
92

hydrogen-react

Reusable components and utilities for building Shopify-powered custom storefronts.
TypeScript
174
star
93

ui-extensions

TypeScript
173
star
94

storefront-api-learning-kit

JavaScript
171
star
95

heap-profiler

Ruby heap profiler
C++
159
star
96

autoload_reloader

Experimental implementation of code reloading using Ruby's autoload
Ruby
158
star
97

app_profiler

Collect performance profiles for your Rails application.
Ruby
157
star
98

graphql-metrics

Extract as much much detail as you want from GraphQL queries, served up from your Ruby app and the graphql gem.
Ruby
157
star
99

active_fulfillment

Active Merchant library for integration with order fulfillment services
Ruby
155
star
100

ci-queue

Distribute tests over many workers using a queue
Ruby
148
star