--- - name: Validate deployment settings ansible.builtin.assert: that: - kraken_bot_image | length > 0 - kraken_bot_dashboard_password | length >= 16 - kraken_bot_replicas | int == 1 - kraken_bot_config is mapping - kraken_bot_config.strategies is defined - >- (not (kraken_bot_live_trading_enabled | bool)) or ((kraken_bot_api_key | length > 0) and (kraken_bot_api_secret | length > 0)) - >- (kraken_bot_live_trading_enabled | bool) or (kraken_bot_config.strategies | selectattr('mode', 'defined') | selectattr('mode', 'equalto', 'live') | list | length == 0) fail_msg: >- Set kraken_bot_image and a dashboard password of at least 16 characters. Live mode additionally requires kraken_bot_live_trading_enabled=true and Kraken API credentials. This role only supports one replica because all strategies share the same account and persistent state. - name: Create application namespace kubernetes.core.k8s: state: present definition: apiVersion: v1 kind: Namespace metadata: name: "{{ kraken_bot_namespace }}" labels: app.kubernetes.io/name: "{{ kraken_bot_name }}" app.kubernetes.io/managed-by: ansible kubeconfig: "{{ kraken_bot_kubeconfig | default(omit, true) }}" context: "{{ kraken_bot_kube_context | default(omit, true) }}" - name: Create persistent application data volume kubernetes.core.k8s: state: present definition: apiVersion: v1 kind: PersistentVolumeClaim metadata: name: "{{ kraken_bot_name }}-data" namespace: "{{ kraken_bot_namespace }}" spec: accessModes: - ReadWriteOnce resources: requests: storage: "{{ kraken_bot_storage_size }}" storageClassName: "{{ kraken_bot_storage_class | default(omit, true) }}" kubeconfig: "{{ kraken_bot_kubeconfig | default(omit, true) }}" context: "{{ kraken_bot_kube_context | default(omit, true) }}" - name: Create strategy configuration kubernetes.core.k8s: state: present definition: apiVersion: v1 kind: ConfigMap metadata: name: "{{ kraken_bot_name }}-config" namespace: "{{ kraken_bot_namespace }}" data: strategies.yaml: "{{ kraken_bot_config | to_nice_yaml(indent=2, sort_keys=false) }}" kubeconfig: "{{ kraken_bot_kubeconfig | default(omit, true) }}" context: "{{ kraken_bot_kube_context | default(omit, true) }}" - name: Create credentials secret kubernetes.core.k8s: state: present definition: apiVersion: v1 kind: Secret metadata: name: "{{ kraken_bot_name }}-secrets" namespace: "{{ kraken_bot_namespace }}" type: Opaque stringData: KRAKEN_API_KEY: "{{ kraken_bot_api_key }}" KRAKEN_API_SECRET: "{{ kraken_bot_api_secret }}" DASHBOARD_USERNAME: "{{ kraken_bot_dashboard_username }}" DASHBOARD_PASSWORD: "{{ kraken_bot_dashboard_password }}" kubeconfig: "{{ kraken_bot_kubeconfig | default(omit, true) }}" context: "{{ kraken_bot_kube_context | default(omit, true) }}" no_log: true - name: Deploy continuous trading service kubernetes.core.k8s: state: present definition: apiVersion: apps/v1 kind: Deployment metadata: name: "{{ kraken_bot_name }}" namespace: "{{ kraken_bot_namespace }}" labels: app.kubernetes.io/name: "{{ kraken_bot_name }}" spec: replicas: 1 strategy: type: Recreate selector: matchLabels: app.kubernetes.io/name: "{{ kraken_bot_name }}" template: metadata: labels: app.kubernetes.io/name: "{{ kraken_bot_name }}" annotations: kraken-bot/config-sha256: "{{ kraken_bot_config | to_nice_yaml(indent=2, sort_keys=false) | hash('sha256') }}" spec: automountServiceAccountToken: false securityContext: runAsNonRoot: true runAsUser: 10001 runAsGroup: 10001 fsGroup: 10001 seccompProfile: type: RuntimeDefault containers: - name: kraken-trader image: "{{ kraken_bot_image }}" imagePullPolicy: "{{ kraken_bot_image_pull_policy }}" ports: - name: http containerPort: 8080 protocol: TCP env: - name: CONFIG_PATH value: /config/strategies.yaml - name: DATA_DIR value: /data - name: HOST value: 0.0.0.0 - name: PORT value: "8080" - name: LIVE_TRADING_ENABLED value: "{{ kraken_bot_live_trading_enabled | bool | string | lower }}" - name: LOG_LEVEL value: "{{ kraken_bot_log_level }}" - name: KRAKEN_API_KEY valueFrom: secretKeyRef: name: "{{ kraken_bot_name }}-secrets" key: KRAKEN_API_KEY - name: KRAKEN_API_SECRET valueFrom: secretKeyRef: name: "{{ kraken_bot_name }}-secrets" key: KRAKEN_API_SECRET - name: DASHBOARD_USERNAME valueFrom: secretKeyRef: name: "{{ kraken_bot_name }}-secrets" key: DASHBOARD_USERNAME - name: DASHBOARD_PASSWORD valueFrom: secretKeyRef: name: "{{ kraken_bot_name }}-secrets" key: DASHBOARD_PASSWORD volumeMounts: - name: data mountPath: /data - name: config mountPath: /config readOnly: true - name: tmp mountPath: /tmp livenessProbe: httpGet: path: /healthz port: http initialDelaySeconds: 30 periodSeconds: 30 failureThreshold: 3 readinessProbe: httpGet: path: /healthz port: http periodSeconds: 15 resources: requests: cpu: 50m memory: 256Mi limits: memory: 512Mi securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: - ALL volumes: - name: data persistentVolumeClaim: claimName: "{{ kraken_bot_name }}-data" - name: config configMap: name: "{{ kraken_bot_name }}-config" - name: tmp emptyDir: {} kubeconfig: "{{ kraken_bot_kubeconfig | default(omit, true) }}" context: "{{ kraken_bot_kube_context | default(omit, true) }}" - name: Expose dashboard inside the cluster kubernetes.core.k8s: state: present definition: apiVersion: v1 kind: Service metadata: name: "{{ kraken_bot_name }}" namespace: "{{ kraken_bot_namespace }}" spec: type: "{{ kraken_bot_service_type }}" selector: app.kubernetes.io/name: "{{ kraken_bot_name }}" ports: - name: http port: 80 targetPort: http protocol: TCP kubeconfig: "{{ kraken_bot_kubeconfig | default(omit, true) }}" context: "{{ kraken_bot_kube_context | default(omit, true) }}"