A Concourse resource for retrieving resources
from a kubernetes cluster, along with a general purpose put
for running any kubectl
command.
-
url
: Required. The kubernetes server URL, e.g."https://my-cluster:8443"
. -
token
: Required. Authorization token for the api server. -
certificate_authority
: Required. The certificate authority for the api server.certificate_authority: | -----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----
-
insecure_skip_tls_verify
: Optional. Iftrue
, ignorescertificate_authority
and skips the validity check of the kubernetes server’s certificate. Default isfalse
.🔥Use with caution. This makes the HTTPS connection insecure! -
resource_types
: Optional. Comma separated list of resource type(s) to retrieve (defaults to justpod
).resource_types: deployment,service,pod
-
namespace
: Optional. The namespace to restrict the query to.
Forcheck
/get
, this will default to all namespaces (--all-namespaces
).
Forput
, this will default to remaining unset (not specified), but can be overridden with a step param (see below). -
filter
: Optional. Can contain any/all the following criteria:-
selector
: Specify a label--selector
for the query. Can use any valid label selector expression. Defaults to empty.source: filter: selector: app=my-app,app.kubernetes.io/component in (frontend, backend)
ℹ️Selectors are the only filter that are performed server-side, and can help cull down the response before it passes through the rest of the filters (below). This can speed up check
operations when dealing with a potentially large volume of resources. -
name
: Matches against themetadata.name
of the resource. Supports both literal (my-ns-1
) and regular expressions ("my-ns-[0-9]*$"
).source: filter: name: "my-ns-[0-9]*$"
-
olderThan
: Time in seconds that themetadata.creationTimestamp
must be older than (ex:86400
for 24hrs).source: filter: olderThan: 86400
-
youngerThan
: Time in seconds that themetadata.creationTimestamp
must be younger than (ex:3600
for 1hr).source: filter: youngerThan: 3600
-
phases
: List ofstatus.phase
value(s) the resource must match at least one of. This varies depending on the resource. For example, a pod’s status can be one ofPending
,Running
,Succeeded
,Failed
orUnknown
. To retrieve onlyFailed
orUnknown
pods:source: filter: phases: - Failed - Unknown
-
jq
: Apply any other custom filter(s) on the JSON returned bykubectl
. For example, to retrieve only resources whose image comes from the registryregistry.acme.io
:source: filter: jq: - '.spec.containers[] | .image | startswith("registry.acme.io")'
We can add multiple filters that are (by default) "OR’d" together. For example, to also look for any resource with a container that has restarted more than
10
times:source: filter: jq: - '.spec.containers[] | .image | startswith("registry.acme.io")' - '.status.containerStatuses[] | .restartCount > 10'
💡This is advanced usage and requires good knowledge about jq and the Kubernetes API. Best approach to writing such queries is to experiment directly with
kubectl
andjq
:kubectl ... get ... -o json | jq <query>
When at least one
jq
filter is present, the following additional options can be configured (optionally):-
jq_operator
: Defaults to,
- the basic identity operator which combines them as "OR". It can be any filter joining operationjq
understands, including+
and-
(see jq Manual: Basic Filters). Building on the example above, if we wanted to constrain the matches to only resources that matched both filters together, we can use theand
operator:source: filter: jq: - '.spec.containers[] | .image | startswith("registry.acme.io")' - '.status.containerStatuses[] | .restartCount > 10' jq_operator: 'and'
-
jq_transform
: Defaults to empty (do nothing) - specifies a final JSON transform of the result(s) matched by the list ofjq
queries. It can be used to alter the structure of the matched json or even produce a completely new json. The interactive equivalent to this is:kubectl ... get ... -o json | jq "[.[] | select( $MATCH_QUERY ) ] | unique $TRANSFORM_QUERY"
⚠️ Use with caution. Whatever the transformation is, it should also include the
metadata: {uid: "…", resourceVersion: "…"}
structure, because this is reported to Concourse as the result of the check. See here for an example.The empty result
[]
appears to not be considered a new version by Concourse (does not trigger a job) - the transform query can make use of that in a condition where it does not want to produce a new version.
-
-
-
sensitive
: Optional. Iftrue
, the resource content will be considered sensitive and not show up in the logs or Concourse UI. Can be overridden as a param to eachget
step. Default isfalse
.
The current list of resource_types
resources are fetched from the cluster, and filtered against any filter
criteria configured.
Each matching resource is emitted as a separate version, uniquely identified by its uid
/resourceVersion
pair.
New versions will be triggered by encountering any of:
-
new
uid
not seen before -
new
resourceVersion
for auid
(that was previously seen at a differentresourceVersion
)
ℹ️
|
Due to the way Concourse treats the versions from the first check , this resource will emit only a
single initial resource version (or zero if none match). It will be the first resource in the list returned from the query.
All subsequent check invocations after that will always emit the full batch of resources as individual versions.
This is done to give pipelines the opportunity to run across each k8s resource. Otherwise, if all versions were emitted
from the first initial check , Concourse would only trigger on the last version in the list.
|
Retrieve the single resource as JSON (-o json
) and writes it to a file resource.json
.
{
"apiVersion": "v1",
"kind": "...",
"metadata": {...},
...
}
General purpose execution of kubectl
with args provided as a param to put
.
-
kubectl
: Required. The args to pass directly tokubectl
.ℹ️The --server
,--token
,--certificate-authority
and--namespace
will all be implicitly included in the command based on thesource
configuration. -
namespace
: Optional. Overrides the source configuration’s value for this particularput
step. -
await
: Optional. Configures theput
step to poll the cluster (after running thekubectl
command) for resources and await certain conditions before succeeding. Has the following configuration:-
timeout
: Required. Must be a positive integer to enable waiting (anything else disables waiting). Measured in seconds. -
interval
: Optional. Polling interval, measured in seconds (defaults to3
). -
resource_types
: Optional. Overrides the source configresources_types
for what to retrieve from the cluster and run through theconditions
. -
conditions
: Optional. List of zero or morejq
expressions to evaluate. If none are given, default expressions are inferred based on theresource_types
being retrieved.
-
Wait conditions are expressed as jq
expressions listed under await.conditions
in the put
step params
(similar to the filter.jq
list in source
configuration of the resource).
The conditions are given each resource’s root JSON object.
- put: k8s
params:
kubectl: create deployment my-nginx --image=nginx
await:
timeout: 30 # seconds
resource_types: deployment
conditions:
- select(.spec.replicas > 0) | .status.readyReplicas > 0
-
Can list zero or more conditions (see defaults below for when none are given).
-
Each expression must evaluate to a boolean result (
true
orfalse
), all other results are ignored. -
All conditions must produce at least one
true
result, and nofalse
results. -
If the
timeout
is reached before the conditions are satisfied,put
will fail.
❗
|
Be sure to craft your expressions to safely filter out or ignore any resources you don’t care about, taking note of the resource_types you are querying for. Any false result will in any condition will prevent the wait from succeeding.
|
If no conditions
are given, wait will attempt to infer sensible default conditions based on the resource_types
.
The table below list the conditions that are used by default.
resource_types |
Default Condition |
---|---|
|
|
|
|
|
|
|
|
ℹ️
|
The default source config resource_types is pod .
|
The pipeline below checks for kubernetes namespaces
named my-ns-<number>
created more than 24 hours ago.
resource_types:
- name: k8s-resource
type: docker-image
source:
repository: jgriff/k8s-resource
resources:
- name: expired-namespace
type: k8s-resource
icon: kubernetes
source:
url: ((k8s-server))
token: ((k8s-token))
certificate_authority: ((k8s-ca))
resource_types: namespaces (1)
filter:
name: "my-ns-[0-9]*$" (2)
olderThan: 86400 (3)
jobs:
- name: view-expired-namespaces
plan:
- get: expired-namespace
version: every
trigger: true
- task: take-a-look
config:
platform: linux
image_resource:
type: registry-image
source: { repository: busybox }
inputs:
- name: expired-namespace
run:
path: cat
args: ["expired-namespace/resource.json"]
-
are
namespaces
. -
are named
my-ns-<number>
(e.gmy-ns-1
,my-ns-200
, etc). -
have existed for longer than 24 hours (
86400
seconds).
Each k8s resource that matches the above criteria is emitted individually from the expired-namespace
resource,
and then the take-a-look
task echoes the contents of the retrieved resource file (for demonstration purposes).
ℹ️
|
Be sure to include version: every in your get step so you get every k8s resource that matches your query.
Otherwise, Concourse will only trigger on the latest resource to be emitted (the last one in the list that comes back from the query).
|
The pipeline below demonstrates using the put
operation to deploy a resource file deploy.yaml
from a git repo my-k8s-repo
(config not shown).
resource_types:
- name: k8s-resource
type: docker-image
source:
repository: jgriff/k8s-resource
resources:
- name: k8s
type: k8s-resource
icon: kubernetes
source:
url: ((k8s-server))
token: ((k8s-token))
certificate_authority: ((k8s-ca))
jobs:
- name: deploy-prod
plan:
- get: my-k8s-repo
trigger: true
- put: k8s
params:
kubectl: apply -f my-k8s-repo/deploy.yaml
namespace: prod
Here’s the same example as above, with the added await
behavior where put
will wait up to 2 minutes for the deployment to come up.
If the deployment isn’t ready after 2 minutes, put
will fail.
resource_types:
- name: k8s-resource
type: docker-image
source:
repository: jgriff/k8s-resource
resources:
- name: k8s
type: k8s-resource
icon: kubernetes
source:
url: ((k8s-server))
token: ((k8s-token))
certificate_authority: ((k8s-ca))
jobs:
- name: deploy-prod
plan:
- get: my-k8s-repo
trigger: true
- put: k8s
params:
kubectl: apply -f my-k8s-repo/deploy.yaml
namespace: prod
await:
timeout: 120
resource_types: deployment
Since await
uses check
to retrieve the resources, all the source.filter
options are available to you when querying for resources to check against your conditions.
For example:
resources:
- name: k8s
type: k8s-resource
icon: kubernetes
source:
url: ((k8s-server))
token: ((k8s-token))
certificate_authority: ((k8s-ca))
namespace: prod
resource_types: deployment
filter:
selector: app=my-app,app.kubernetes.io/component in (frontend, backend)
name: "my-*"
jobs:
- name: deploy-prod
plan:
- get: my-k8s-repo
trigger: true
- put: k8s
params:
kubectl: apply -f my-k8s-repo/deploy.yaml
await:
timeout: 120
This will:
-
Apply our deployment from
deploy.yaml
. -
Then wait at most 2 minutes for all deployments to reach a ready state (default condition for
deployment
resource types) whose:-
name starts with
"my-"
. -
have a metadata label
"app.kubernetes.io/component"
of either"frontend"
or"backend"
.
-
You can supply any custom condition to await
on.
jobs:
- name: deploy-prod
plan:
- get: my-k8s-repo
trigger: true
- put: k8s
params:
kubectl: apply -f my-k8s-repo/deploy.yaml
namespace: prod
await:
timeout: 120
resource_types: deployment,statefulset
conditions:
- select(.metadata.name == "my-deployment") | .status.readyReplicas > 0
- select(.metadata.name == "my-statefulset") | .status.readyReplicas > 0
The pipeline below demonstrates using both get
and put
in the same pipeline.
|
Don’t use the same So the best way to deal with this is to use one resource instance for the resources you are |
Here’s an example that combines the previous 2 examples into a single pipeline that watches for expired namespaces, and then deletes them.
k8s-resource-source-config: &k8s-resource-source-config
url: ((k8s-server))
token: ((k8s-token))
certificate_authority: ((k8s-ca))
resource_types:
- name: k8s-resource
type: docker-image
source:
repository: jgriff/k8s-resource
resources:
- name: k8s
type: k8s-resource
icon: kubernetes
source:
<< : *k8s-resource-source-config
- name: expired-namespace
type: k8s-resource
icon: kubernetes
source:
<< : *k8s-resource-source-config
resource_types: namespaces
filter:
name: "my-ns-[0-9]*$"
olderThan: 86400
phases: [Active]
jobs:
- name: delete-expired-namespaces
plan:
- get: expired-namespace
version: every
trigger: true
- load_var: expired-namespace-resource
file: expired-namespace/resource.json
- put: k8s
params:
kubectl: delete namespace ((.:expired-namespace-resource.metadata.name))