How to parameterize a workflowTempateRef? - argoproj

I have a WorkflowTemplate "nyc-test-template" which I trigger via Argo Events and PubSub. So, if I publish a message {} into the PubSub topic "argo-events-nyc" the template specified via a workflowTempateRef is started. That does work just fine. Now I want to parameterize the to be started template.
My not-working draft looks as follows:
apiVersion: argoproj.io/v1alpha1
kind: EventSource
metadata:
name: pubsub-event-source-nyc
spec:
template:
serviceAccountName: argo-events
pubSub:
examplex:
jsonBody: true
topic: argo-events-nyc
subscriptionID: argo-events-nyc-sub
---
apiVersion: argoproj.io/v1alpha1
kind: Sensor
metadata:
name: pubsub-sensor-nyc
spec:
template:
serviceAccountName: argo-events-sa
dependencies:
- name: pubsub-event-source-dep
eventSourceName: pubsub-event-source-nyc
eventName: examplex
triggers:
- template:
name: argo-workflow-trigger
argoWorkflow:
group: argoproj.io
version: v1alpha1
resource: workflows
operation: submit
source:
resource:
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: nyc-test-template-
namespace: argo
spec:
arguments:
parameters:
- name: wft
value: nyc-test-template
workflowTemplateRef:
# I'm pretty sure this inputs block is useless. But leaving it out
# and instead referencing arguments.parameters.wft won't work either.
inputs:
parameters:
- name: wft
name: "{{inputs.parameters.wft}}"
parameters:
- src:
dependencyName: pubsub-event-source-dep
dataKey: body.wft
dest: spec.arguments.parameters.0.value
What I would like to happen is this:
an empty message {} would trigger "nyc-test-template"
the message {"wft": "my-template"} would trigger "my-template"
Instead publishing an empty message will cause the Sensor to throw an error:
2021-03-29T15:31:16.386441528Z2021/03/29 15:31:16 Failed to parse workflow: error unmarshaling JSON: while decoding JSON: json: unknown field "inputs"
Frankly speaking - above yaml took crude inspiration from this example. It's not really the result of an educated guess as I still don't understand the mechanics of how parameters, arguments and inputs are interacting.

You can use when to toggle which template to use depending on a parameter.
Suppose I have two simple WorkflowTemplates like these:
apiVersion: argoproj.io/v1alpha1
kind: WorkflowTemplate
metadata:
name: t1
spec:
templates:
- name: whalesay-template
container:
image: docker/whalesay
command: [cowsay]
args: [t1]
---
apiVersion: argoproj.io/v1alpha1
kind: WorkflowTemplate
metadata:
name: t2
spec:
templates:
- name: whalesay-template
container:
image: docker/whalesay
command: [cowsay]
args: [t2]
I can choose to execute one or another template from the WorkflowTemplates depending on an argument passed to a Workflow (either manually or from an argo-events setup).
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: switch-
spec:
entrypoint: pick
arguments:
parameters:
- name: which
templates:
- name: pick
steps:
- - name: t1
when: "{{workflow.parameters.which}} == t1"
templateRef:
name: t1
template: whalesay-template
- name: t2
when: "{{workflow.parameters.which}} == t2"
templateRef:
name: t2
template: whalesay-template
For top-level arguments to a Workflow, you can use workflow.parameters.SOMETHING.
Building on the above, you can use a JSON parsing tool like jq to retrieve toggle value and then choose your template based on that value.
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: switch-
spec:
entrypoint: pick
arguments:
parameters:
- name: json
templates:
- name: pick
steps:
- - name: parse
template: parse
- - name: t1
when: "{{steps.parse.outputs.result}} == a"
templateRef:
name: t1
template: whalesay-template
- name: t2
when: "{{steps.parse.outputs.result}} == b"
templateRef:
name: t2
template: whalesay-template
- name: parse
container:
image: jorgeandrada/alpine-jq
command: [sh, -c]
env:
- name: JSON
value: "{{workflow.parameters.json}}"
args: [echo "$JSON" | jq -j '.test']
I should mention that using jq is a bit heavy-handed. In future versions of Argo (3.1+) there will be tools to inspect JSON more directly. But this solution is nicely reverse-compatible.

Credits go to Derek Wang.
apiVersion: argoproj.io/v1alpha1
kind: Sensor
metadata:
name: pubsub-sensor-nyc
spec:
template:
serviceAccountName: argo-events-sa
dependencies:
- name: pubsub-event-source-dep
eventSourceName: pubsub-event-source-nyc
eventName: examplex
triggers:
- template:
name: argo-workflow-trigger
argoWorkflow:
group: argoproj.io
version: v1alpha1
resource: workflows
operation: submit
source:
resource:
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: nyc-test-template-
namespace: argo
spec:
workflowTemplateRef:
name: nyc-test-template
parameters:
- src:
dependencyName: pubsub-event-source-dep
dataKey: body.wft
value: nyc-test-template # default value
dest: spec.workflowTemplateRef.name # <- this

Related

Disable Istio sidecar injection to the job pod

How to disable Istio sidecar injection for the Kubernetes Job?
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: pod-restart
spec:
concurrencyPolicy: Forbid
schedule: '0 8 * * *'
jobTemplate:
metadata:
annotations:
sidecar.istio.io/inject: "false"
spec:
backoffLimit: 2
activeDeadlineSeconds: 600
template:
spec:
serviceAccountName: pod-restart
restartPolicy: Never
containers:
- name: kubectl
image: bitnami/kubectl
command: ['kubectl', 'rollout', 'restart', 'deployment/myapp']
Sidecar still gets injected.
The annotation is in wrong place. You have to put it on the pod template.
apiVersion: batch/v1beta1
kind: CronJob
metadata:
spec:
jobTemplate:
spec:
template:
metadata:
annotations:
sidecar.istio.io/inject: "false"
There is working CronJob example with istio injection disabled.
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: hello
spec:
schedule: "*/1 * * * *"
jobTemplate:
spec:
template:
metadata:
annotations:
sidecar.istio.io/inject: "false"
spec:
containers:
- name: hello
image: busybox
args:
- /bin/sh
- -c
- date; echo "Hello, World!"
restartPolicy: OnFailure
Also there is related github issue about that.
Now the annotation has been deprecated as per doc https://istio.io/latest/docs/reference/config/annotations/
it would be best if you use a label instead:
apiVersion: batch/v1
kind: CronJob
metadata:
name: jobs-cleanup
spec:
schedule: "*/4 * * * *"
successfulJobsHistoryLimit: 1
jobTemplate:
spec:
template:
metadata:
labels:
sidecar.istio.io/inject: "false"
spec:
serviceAccountName: cleaner
containers:
- name: kubectl-container
image: bitnami/kubectl:latest
command: ["sh", "/tmp/clean.sh"]
volumeMounts:
- name: cleaner-script
mountPath: /tmp/
restartPolicy: Never
volumes:
- name: cleaner-script
configMap:
name: cleaner-script

OpenShift : Build failed with 'Invalid Output reference'

I am creating a build configuration with the following YAML. Then, I trigger the build manually with oc. So, the following commands are run.
oc create -f mybuildconfig.yaml
oc start-build bc/ns-bc-myproject --wait
Build configuration YAML:
apiVersion: v1
kind: BuildConfig
metadata:
labels:
build: myproject
name: ns-bc-myproject
namespace: ns
spec:
output:
to:
kind: ImageStreamTag
name: 'ns-is-myproject:latest'
postCommit: {}
resources: {}
runPolicy: Serial
source:
git:
ref: dev_1.0
uri: 'https://github.com/ns/myproject.git'
type: Git
strategy:
sourceStrategy:
from:
kind: ImageStreamTag
name: 'nodejs:10'
namespace: openshift
type: Source
successfulBuildsHistoryLimit: 5
The build never goes through; it keeps failing with the message as Invalid output reference. What is missing?
You need to create an image stream in the namespace where your build config is pushing the image to.
Something like this will work for you:
- apiVersion: v1
kind: ImageStream
metadata:
labels:
application: ns-is-myproject
name: ns-is-myproject
namespace: ns-is-myproject

RabbitMQ only shows one node

I have been trying to set up RabbitMQ on a k8s cluster, I finally got everything set up, but only one node shows up on the managementUI. Here are my steps:
1. Dockerfile Setup
I do this to enable autocluster:
FROM rabbitmq:3.8-rc-management-alpine
MAINTAINER kevlai
RUN rabbitmq-plugins --offline enable rabbitmq_peer_discovery_k8s
2. Set up RBAC
apiVersion: v1
kind: ServiceAccount
metadata:
name: borecast-rabbitmq
namespace: borecast-production
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: borecast-rabbitmq
namespace: borecast-production
rules:
- apiGroups:
- ""
resources:
- endpoints
verbs:
- get
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: borecast-rabbitmq
namespace: borecast-production
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: dev
subjects:
- kind: ServiceAccount
name: borecast-rabbitmq
namespace: borecast-production
3. Set up Secrets
apiVersion: v1
kind: Secret
metadata:
name: rabbitmq-secret
namespace: borecast-production
type: Opaque
data:
username: a2V2
password: Ym9yZWNhc3RydWx6
secretCookie: c2VjcmV0Y29va2llaGVyZQ==
4. Set up StorageClass
I'm setting up StorageClass so k8s will automatically do provision for me on AWS.
kind: StorageClass
apiVersion: storage.k8s.io/v1beta1
metadata:
name: rabbitmq-sc
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp2
zone: us-east-2a
reclaimPolicy: Retain
5. Set up StatefulSets and Services
You can see there are two services. The headless service is for the pods themselves. As for the management service, I'll expose the service for an Ingress controller in order for it to be accessible from outside.
---
apiVersion: v1
kind: Service
metadata:
name: borecast-rabbitmq-management-service
namespace: borecast-production
labels:
app: borecast-rabbitmq
spec:
ports:
- port: 15672
targetPort: 15672
name: http
- port: 5672
targetPort: 5672
name: amqp
selector:
app: borecast-rabbitmq
---
apiVersion: v1
kind: Service
metadata:
name: borecast-rabbitmq-service
namespace: borecast-production
labels:
app: borecast-rabbitmq
spec:
clusterIP: None
ports:
- port: 5672
name: amqp
selector:
app: borecast-rabbitmq
---
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: borecast-rabbitmq
namespace: borecast-production
spec:
serviceName: borecast-rabbitmq-service
replicas: 3
template:
metadata:
labels:
app: borecast-rabbitmq
spec:
serviceAccountName: borecast-rabbitmq
containers:
- image: docker.borecast.com/borecast-rabbitmq:v1.0.3
name: borecast-rabbitmq
imagePullPolicy: Always
resources:
requests:
memory: "256Mi"
cpu: "150m"
limits:
memory: "512Mi"
cpu: "250m"
ports:
- containerPort: 5672
name: amqp
env:
- name: RABBITMQ_DEFAULT_USER
valueFrom:
secretKeyRef:
name: rabbitmq-secret
key: username
- name: RABBITMQ_DEFAULT_PASS
valueFrom:
secretKeyRef:
name: rabbitmq-secret
key: password
- name: RABBITMQ_ERLANG_COOKIE
valueFrom:
secretKeyRef:
name: rabbitmq-secret
key: secretCookie
- name: MY_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: K8S_SERVICE_NAME
# value: borecast-rabbitmq-service.borecast-production.svc.cluster.local
value: borecast-rabbitmq-service
- name: RABBITMQ_USE_LONGNAME
value: "true"
- name: RABBITMQ_NODENAME
value: "rabbit#$(MY_POD_NAME).$(K8S_SERVICE_NAME)"
# value: rabbit#$(MY_POD_NAME).borecast-rabbitmq-service.borecast-production.svc.cluster.local
- name: RABBITMQ_NODE_TYPE
value: disc
- name: AUTOCLUSTER_TYPE
value: "k8s"
- name: AUTOCLUSTER_DELAY
value: "10"
- name: AUTOCLUSTER_CLEANUP
value: "true"
- name: CLEANUP_WARN_ONLY
value: "false"
- name: K8S_ADDRESS_TYPE
value: "hostname"
- name: K8S_HOSTNAME_SUFFIX
value: ".$(K8S_SERVICE_NAME)"
# value: .borecast-rabbitmq-service.borecast-production.svc.cluster.local
volumeMounts:
- name: rabbitmq-volume
mountPath: /var/lib/rabbitmq
imagePullSecrets:
- name: regcred
volumeClaimTemplates:
- metadata:
name: rabbitmq-volume
namespace: borecast-production
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: rabbitmq-sc
resources:
requests:
storage: 5Gi
Problem
Everything is working. However, when I access the management UI (i.e. I'm access the borecast-rabbitmq-management-service, port 15672), I only see one node showing up, when it should be three:
Also notice that the cluster name is
rabbit#borecast-rabbitmq-0.borecast-rabbitmq-service.borecast-production.svc.cluster.local
but when I log out and log in again, sometimes the number 0 will be changed to 1 or 2 for borecast-rabbitmq-0.
And also notice the node name is
rabbit#borecast-rabbitmq-1.borecast-rabbitmq-service
And you guessed it, sometimes the number is 2 or 0 for borecast-rabbitmq-1.
I have been trying to debug but to no avail. The logs for each pod doesn't raise any suspicions and every service and statefulset are working normally. I repeated the five steps multiple times, and if your cluster is on AWS, you can totally replicate my setup by following the steps (after creating the namespace borecast-production of course). If anybody can shed some light on the matter, I'll be eternally grateful.
The problem is with the headless service name definition:
- name: K8S_SERVICE_NAME
# value: borecast-rabbitmq-service.borecast-production.svc.cluster.local
value: borecast-rabbitmq-service
which is a building block of node name:
- name: RABBITMQ_NODENAME
value: "rabbit#$(MY_POD_NAME).$(K8S_SERVICE_NAME)"
whereas the proper node name, should be of FQDN of the POD (<statefulset name>-<ordinal index>.<headless_svc_name>.<namespace>.svc.cluster.local):
- name: RABBITMQ_NODENAME
value: "rabbit#$(MY_POD_NAME).$(K8S_SERVICE_NAME).$(MY_POD_NAMESPACE).svc.cluster.local"
Therefore you ended up with NodeName
borecast-rabbitmq-1.borecast-rabbitmq-service
instead of:
borecast-rabbitmq-1.borecast-rabbitmq-service.borecast-production.svc.cluster.local
Look up the fqdn of the pod created by borecast-rabbitmq StatefulSet (in other word: SRV records of the Pods) with nslookup util from inside of your cluster as explained here, to see what form the RABBITMQ_NODENAME is expected to have.
try exposing 4369 for headless service;
https://www.rabbitmq.com/clustering.html
see the port access section
Had the same issue, and it came down to
Deleting all the rabbitmq resources including the pvc created under the statefulset.
Then reinstalling everything from the manifests.

Failed to connect to cloud SQL using proxy despite following the documentation

I'm using doctrine ORM with Symfony, the PHP framework. I'm getting bizarre behaviour when trying to connect to cloud SQL using GKE.
I'm able to get a connection to the DB via doctrine on command line, for example php bin/console doctrine:database:create is successful and I can see a connection opened in the proxy pod logs.
But when I try and connect to the DB via doctrine in my application I run into this error without fail:
An exception occurred in driver: SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Name or service not known
I have been trying to get my head around this but it doesn't make sense, why would I be able to connect via command line but not in my application?
I followed the documentation here for setting up a db connection using cloud proxy. This is my Kubernetes deployment:
---
apiVersion: "extensions/v1beta1"
kind: "Deployment"
metadata:
name: "riptides-api"
namespace: "default"
labels:
app: "riptides-api"
microservice: "riptides"
spec:
replicas: 3
selector:
matchLabels:
app: "riptides-api"
microservice: "riptides"
template:
metadata:
labels:
app: "riptides-api"
microservice: "riptides"
spec:
containers:
- name: "api-sha256"
image: "eu.gcr.io/riptides/api#sha256:ce0ead9d1dd04d7bfc129998eca6efb58cb779f4f3e41dcc3681c9aac1156867"
env:
- name: DB_HOST
value: 127.0.0.1:3306
- name: DB_USER
valueFrom:
secretKeyRef:
name: riptides-mysql-user-skye
key: user
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: riptides-mysql-user-skye
key: password
- name: DB_NAME
value: riptides
lifecycle:
postStart:
exec:
command: ["/bin/bash", "-c", "php bin/console doctrine:migrations:migrate -n"]
volumeMounts:
- name: keys
mountPath: "/app/config/jwt"
readOnly: true
- name: cloudsql-proxy
image: gcr.io/cloudsql-docker/gce-proxy:1.11
command: ["/cloud_sql_proxy",
"-instances=riptides:europe-west4:riptides-sql=tcp:3306",
"-credential_file=/secrets/cloudsql/credentials.json"]
# [START cloudsql_security_context]
securityContext:
runAsUser: 2 # non-root user
allowPrivilegeEscalation: false
# [END cloudsql_security_context]
volumeMounts:
- name: riptides-mysql-service-account
mountPath: /secrets/cloudsql
readOnly: true
volumes:
- name: keys
secret:
secretName: riptides-api-keys
items:
- key: private.pem
path: private.pem
- key: public.pem
path: public.pem
- name: riptides-mysql-service-account
secret:
secretName: riptides-mysql-service-account
---
apiVersion: "autoscaling/v2beta1"
kind: "HorizontalPodAutoscaler"
metadata:
name: "riptides-api-hpa"
namespace: "default"
labels:
app: "riptides-api"
microservice: "riptides"
spec:
scaleTargetRef:
kind: "Deployment"
name: "riptides-api"
apiVersion: "apps/v1beta1"
minReplicas: 1
maxReplicas: 5
metrics:
- type: "Resource"
resource:
name: "cpu"
targetAverageUtilization: 70
If anyone has any suggestions I'd be forever greatful
It doesn't look like anything is wrong with your k8s yaml, but more likely in how you are connecting using Symfony. According to the documentation here, Symfony expect the DB URI to be passed in through an environment variable called "DATABASE_URL". See the following example:
# customize this line!
DATABASE_URL="postgres://db_user:db_password#127.0.0.1:5432/db_name"
This was happening because doctrine was using default values instead of the (should be overriding) environment variables I had set up in my deployment. I changed the environment variable names to be different to the default ones and it works

Deploy peromethues in new cluster crd issue

Im trying to create prometheus with operator in fresh new k8s cluster
I use the following files ,
First step I’m creating a namespace monitoring
apply this file , which works ok
apiVersion: apps/v1beta2
kind: Deployment
metadata:
labels:
k8s-app: prometheus-operator
name: prometheus-operator
namespace: monitoring
spec:
replicas: 2
selector:
matchLabels:
k8s-app: prometheus-operator
template:
metadata:
labels:
k8s-app: prometheus-operator
spec:
priorityClassName: "operator-critical"
tolerations:
- key: "WorkGroup"
operator: "Equal"
value: "operator"
effect: "NoSchedule"
- key: "WorkGroup"
operator: "Equal"
value: "operator"
effect: "NoExecute"
containers:
- args:
- --kubelet-service=kube-system/kubelet
- --logtostderr=true
- --config-reloader-image=quay.io/coreos/configmap-reload:v0.0.1
- --prometheus-config-reloader=quay.io/coreos/prometheus-config-reloader:v0.29.0
image: quay.io/coreos/prometheus-operator:v0.29.0
name: prometheus-operator
ports:
- containerPort: 8080
name: http
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
nodeSelector:
serviceAccountName: prometheus-operator
Now I want to apply this file (CRD)
apiVersion: monitoring.coreos.com/v1
kind: Prometheus
metadata:
name: prometheus
namespace: monitoring
labels:
prometheus: prometheus
spec:
replica: 1
priorityClassName: "operator-critical"
serviceAccountName: prometheus
nodeSelector:
worker.garden.sapcloud.io/group: operator
serviceMonitorNamespaceSelector: {}
serviceMonitorSelector:
matchLabels:
role: observeable
tolerations:
- key: "WorkGroup"
operator: "Equal"
value: "operator"
effect: "NoSchedule"
- key: "WorkGroup"
operator: "Equal"
value: "operator"
effect: "NoExecute"
And Im getting error :
error: unable to recognize "1500-prometheus-crd.yaml": no matches for kind "Prometheus" in version "monitoring.coreos.com/v1"
I found this https://github.com/coreos/prometheus-operator/issues/1866 , but I try to do it as mentioned, I.e.
Wait a few second and deploy again but it doesn’t help. Any idea ?
Also tried to delete the ns and create it again with the configs and I got the same issue. please advice
You need to install the custom resources as available objects in Kubernetes before you can create instances of them.