mirror of
https://github.com/BagelHole/DevOps-Security-Agent-Skills.git
synced 2026-08-22 12:49:53 +02:00
.
This commit is contained in:
@@ -0,0 +1,445 @@
|
||||
---
|
||||
name: argocd-gitops
|
||||
description: Implement GitOps with ArgoCD for declarative Kubernetes deployments. Configure applications, manage sync policies, implement progressive delivery, and automate deployments from Git repositories. Use when implementing GitOps workflows or continuous deployment to Kubernetes.
|
||||
license: MIT
|
||||
metadata:
|
||||
author: devops-skills
|
||||
version: "1.0"
|
||||
---
|
||||
|
||||
# ArgoCD GitOps
|
||||
|
||||
Implement declarative continuous delivery for Kubernetes with ArgoCD.
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
Use this skill when:
|
||||
- Implementing GitOps workflows for Kubernetes
|
||||
- Automating deployments from Git repositories
|
||||
- Managing multiple environments declaratively
|
||||
- Implementing progressive delivery strategies
|
||||
- Synchronizing cluster state with Git
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Kubernetes cluster with ArgoCD installed
|
||||
- kubectl configured
|
||||
- Git repository for manifests
|
||||
- ArgoCD CLI (optional)
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
# Create namespace
|
||||
kubectl create namespace argocd
|
||||
|
||||
# Install ArgoCD
|
||||
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
|
||||
|
||||
# Get admin password
|
||||
kubectl -n argocd get secret argocd-initial-admin-secret \
|
||||
-o jsonpath="{.data.password}" | base64 -d
|
||||
|
||||
# Port forward to access UI
|
||||
kubectl port-forward svc/argocd-server -n argocd 8080:443
|
||||
|
||||
# Login with CLI
|
||||
argocd login localhost:8080
|
||||
```
|
||||
|
||||
## Application Definition
|
||||
|
||||
### Basic Application
|
||||
|
||||
```yaml
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: myapp
|
||||
namespace: argocd
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: https://github.com/org/myapp-manifests.git
|
||||
targetRevision: main
|
||||
path: environments/production
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: myapp
|
||||
syncPolicy:
|
||||
automated:
|
||||
prune: true
|
||||
selfHeal: true
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
```
|
||||
|
||||
### Helm Application
|
||||
|
||||
```yaml
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: myapp-helm
|
||||
namespace: argocd
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: https://github.com/org/myapp-chart.git
|
||||
targetRevision: main
|
||||
path: charts/myapp
|
||||
helm:
|
||||
valueFiles:
|
||||
- values.yaml
|
||||
- values-production.yaml
|
||||
parameters:
|
||||
- name: replicaCount
|
||||
value: "3"
|
||||
- name: image.tag
|
||||
value: "2.0.0"
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: myapp
|
||||
syncPolicy:
|
||||
automated:
|
||||
prune: true
|
||||
selfHeal: true
|
||||
```
|
||||
|
||||
### Kustomize Application
|
||||
|
||||
```yaml
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: myapp-kustomize
|
||||
namespace: argocd
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: https://github.com/org/myapp-manifests.git
|
||||
targetRevision: main
|
||||
path: overlays/production
|
||||
kustomize:
|
||||
images:
|
||||
- myapp=myregistry/myapp:2.0.0
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: myapp
|
||||
```
|
||||
|
||||
## Projects
|
||||
|
||||
```yaml
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: AppProject
|
||||
metadata:
|
||||
name: myproject
|
||||
namespace: argocd
|
||||
spec:
|
||||
description: My Project
|
||||
sourceRepos:
|
||||
- https://github.com/org/*
|
||||
destinations:
|
||||
- namespace: myapp-*
|
||||
server: https://kubernetes.default.svc
|
||||
clusterResourceWhitelist:
|
||||
- group: ''
|
||||
kind: Namespace
|
||||
namespaceResourceWhitelist:
|
||||
- group: '*'
|
||||
kind: '*'
|
||||
roles:
|
||||
- name: developer
|
||||
description: Developer role
|
||||
policies:
|
||||
- p, proj:myproject:developer, applications, get, myproject/*, allow
|
||||
- p, proj:myproject:developer, applications, sync, myproject/*, allow
|
||||
groups:
|
||||
- developers
|
||||
```
|
||||
|
||||
## Application Sets
|
||||
|
||||
### Git Generator
|
||||
|
||||
```yaml
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: ApplicationSet
|
||||
metadata:
|
||||
name: myapp-environments
|
||||
namespace: argocd
|
||||
spec:
|
||||
generators:
|
||||
- git:
|
||||
repoURL: https://github.com/org/myapp-manifests.git
|
||||
revision: main
|
||||
directories:
|
||||
- path: environments/*
|
||||
template:
|
||||
metadata:
|
||||
name: 'myapp-{{path.basename}}'
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: https://github.com/org/myapp-manifests.git
|
||||
targetRevision: main
|
||||
path: '{{path}}'
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: 'myapp-{{path.basename}}'
|
||||
syncPolicy:
|
||||
automated:
|
||||
prune: true
|
||||
selfHeal: true
|
||||
```
|
||||
|
||||
### List Generator
|
||||
|
||||
```yaml
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: ApplicationSet
|
||||
metadata:
|
||||
name: myapp-clusters
|
||||
namespace: argocd
|
||||
spec:
|
||||
generators:
|
||||
- list:
|
||||
elements:
|
||||
- cluster: production
|
||||
url: https://prod-cluster.example.com
|
||||
- cluster: staging
|
||||
url: https://staging-cluster.example.com
|
||||
template:
|
||||
metadata:
|
||||
name: 'myapp-{{cluster}}'
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: https://github.com/org/myapp-manifests.git
|
||||
targetRevision: main
|
||||
path: 'environments/{{cluster}}'
|
||||
destination:
|
||||
server: '{{url}}'
|
||||
namespace: myapp
|
||||
```
|
||||
|
||||
### Matrix Generator
|
||||
|
||||
```yaml
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: ApplicationSet
|
||||
metadata:
|
||||
name: myapp-matrix
|
||||
namespace: argocd
|
||||
spec:
|
||||
generators:
|
||||
- matrix:
|
||||
generators:
|
||||
- git:
|
||||
repoURL: https://github.com/org/myapp-manifests.git
|
||||
revision: main
|
||||
directories:
|
||||
- path: apps/*
|
||||
- list:
|
||||
elements:
|
||||
- env: staging
|
||||
- env: production
|
||||
template:
|
||||
metadata:
|
||||
name: '{{path.basename}}-{{env}}'
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: https://github.com/org/myapp-manifests.git
|
||||
targetRevision: main
|
||||
path: '{{path}}/overlays/{{env}}'
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: '{{path.basename}}-{{env}}'
|
||||
```
|
||||
|
||||
## Sync Policies
|
||||
|
||||
### Automated Sync
|
||||
|
||||
```yaml
|
||||
syncPolicy:
|
||||
automated:
|
||||
prune: true # Delete resources not in Git
|
||||
selfHeal: true # Revert manual changes
|
||||
allowEmpty: false # Don't sync empty directories
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
- PrunePropagationPolicy=foreground
|
||||
- PruneLast=true
|
||||
retry:
|
||||
limit: 5
|
||||
backoff:
|
||||
duration: 5s
|
||||
factor: 2
|
||||
maxDuration: 3m
|
||||
```
|
||||
|
||||
### Sync Waves
|
||||
|
||||
```yaml
|
||||
# In Kubernetes manifests
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: myconfig
|
||||
annotations:
|
||||
argocd.argoproj.io/sync-wave: "-1" # Sync first
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: myapp
|
||||
annotations:
|
||||
argocd.argoproj.io/sync-wave: "0" # Sync second
|
||||
```
|
||||
|
||||
### Sync Hooks
|
||||
|
||||
```yaml
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: migration
|
||||
annotations:
|
||||
argocd.argoproj.io/hook: PreSync
|
||||
argocd.argoproj.io/hook-delete-policy: HookSucceeded
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: migrate
|
||||
image: myapp:latest
|
||||
command: ["./migrate.sh"]
|
||||
restartPolicy: Never
|
||||
```
|
||||
|
||||
## CLI Commands
|
||||
|
||||
```bash
|
||||
# List applications
|
||||
argocd app list
|
||||
|
||||
# Get application details
|
||||
argocd app get myapp
|
||||
|
||||
# Sync application
|
||||
argocd app sync myapp
|
||||
|
||||
# Force sync (ignore differences)
|
||||
argocd app sync myapp --force
|
||||
|
||||
# View diff
|
||||
argocd app diff myapp
|
||||
|
||||
# Rollback
|
||||
argocd app rollback myapp
|
||||
|
||||
# Delete application
|
||||
argocd app delete myapp
|
||||
|
||||
# View logs
|
||||
argocd app logs myapp
|
||||
|
||||
# Hard refresh (clear cache)
|
||||
argocd app get myapp --hard-refresh
|
||||
```
|
||||
|
||||
## Repository Configuration
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: private-repo
|
||||
namespace: argocd
|
||||
labels:
|
||||
argocd.argoproj.io/secret-type: repository
|
||||
stringData:
|
||||
url: https://github.com/org/private-repo.git
|
||||
username: git
|
||||
password: ghp_xxxx
|
||||
---
|
||||
# SSH key
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: private-repo-ssh
|
||||
namespace: argocd
|
||||
labels:
|
||||
argocd.argoproj.io/secret-type: repository
|
||||
stringData:
|
||||
url: git@github.com:org/private-repo.git
|
||||
sshPrivateKey: |
|
||||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
...
|
||||
-----END OPENSSH PRIVATE KEY-----
|
||||
```
|
||||
|
||||
## Notifications
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: argocd-notifications-cm
|
||||
namespace: argocd
|
||||
data:
|
||||
service.slack: |
|
||||
token: $slack-token
|
||||
template.app-deployed: |
|
||||
message: Application {{.app.metadata.name}} is now {{.app.status.sync.status}}.
|
||||
trigger.on-deployed: |
|
||||
- when: app.status.operationState.phase in ['Succeeded']
|
||||
send: [app-deployed]
|
||||
```
|
||||
|
||||
## Common Issues
|
||||
|
||||
### Issue: Sync Fails with Diff
|
||||
**Problem**: Resources show differences but are correct
|
||||
**Solution**: Configure ignore differences
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
ignoreDifferences:
|
||||
- group: apps
|
||||
kind: Deployment
|
||||
jsonPointers:
|
||||
- /spec/replicas
|
||||
```
|
||||
|
||||
### Issue: Repository Not Accessible
|
||||
**Problem**: ArgoCD cannot clone repository
|
||||
**Solution**: Check repository secret, verify URL and credentials
|
||||
|
||||
### Issue: Application Stuck OutOfSync
|
||||
**Problem**: Application never becomes synced
|
||||
**Solution**: Check resource status, review events, verify manifests
|
||||
|
||||
### Issue: Health Check Failing
|
||||
**Problem**: Application shows degraded health
|
||||
**Solution**: Check custom health checks, verify probe configurations
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Use ApplicationSets for multi-environment deployments
|
||||
- Implement sync waves for ordered deployments
|
||||
- Use projects to isolate applications
|
||||
- Configure notifications for deployment events
|
||||
- Implement proper RBAC with projects
|
||||
- Use health checks for deployment verification
|
||||
- Enable auto-pruning to remove deleted resources
|
||||
- Keep manifests in dedicated repositories
|
||||
|
||||
## Related Skills
|
||||
|
||||
- [kubernetes-ops](../kubernetes-ops/) - K8s fundamentals
|
||||
- [helm-charts](../helm-charts/) - Helm deployments
|
||||
- [kustomize](../kustomize/) - Kustomize overlays
|
||||
@@ -0,0 +1,126 @@
|
||||
# ArgoCD GitOps Patterns
|
||||
|
||||
## Application Definition
|
||||
|
||||
```yaml
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: myapp
|
||||
namespace: argocd
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: https://github.com/org/repo
|
||||
targetRevision: HEAD
|
||||
path: k8s/overlays/production
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: myapp
|
||||
syncPolicy:
|
||||
automated:
|
||||
prune: true
|
||||
selfHeal: true
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
```
|
||||
|
||||
## Sync Waves
|
||||
|
||||
```yaml
|
||||
metadata:
|
||||
annotations:
|
||||
argocd.argoproj.io/sync-wave: "-1" # Deploy first
|
||||
---
|
||||
metadata:
|
||||
annotations:
|
||||
argocd.argoproj.io/sync-wave: "0" # Default
|
||||
---
|
||||
metadata:
|
||||
annotations:
|
||||
argocd.argoproj.io/sync-wave: "1" # Deploy last
|
||||
```
|
||||
|
||||
## ApplicationSet
|
||||
|
||||
```yaml
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: ApplicationSet
|
||||
metadata:
|
||||
name: myapp-set
|
||||
spec:
|
||||
generators:
|
||||
- list:
|
||||
elements:
|
||||
- env: dev
|
||||
cluster: dev-cluster
|
||||
- env: prod
|
||||
cluster: prod-cluster
|
||||
template:
|
||||
metadata:
|
||||
name: 'myapp-{{env}}'
|
||||
spec:
|
||||
source:
|
||||
repoURL: https://github.com/org/repo
|
||||
path: 'k8s/overlays/{{env}}'
|
||||
destination:
|
||||
server: '{{cluster}}'
|
||||
namespace: myapp
|
||||
```
|
||||
|
||||
## Multi-Cluster
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: prod-cluster
|
||||
labels:
|
||||
argocd.argoproj.io/secret-type: cluster
|
||||
stringData:
|
||||
name: prod
|
||||
server: https://prod-cluster.example.com
|
||||
config: |
|
||||
{
|
||||
"bearerToken": "...",
|
||||
"tlsClientConfig": {
|
||||
"insecure": false,
|
||||
"caData": "..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## App of Apps
|
||||
|
||||
```yaml
|
||||
# Root application
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: root
|
||||
spec:
|
||||
source:
|
||||
path: apps/ # Contains Application manifests
|
||||
destination:
|
||||
namespace: argocd
|
||||
```
|
||||
|
||||
## CLI Commands
|
||||
|
||||
```bash
|
||||
# Login
|
||||
argocd login argocd.example.com
|
||||
|
||||
# Sync
|
||||
argocd app sync myapp
|
||||
argocd app sync myapp --prune
|
||||
|
||||
# Rollback
|
||||
argocd app rollback myapp
|
||||
|
||||
# Diff
|
||||
argocd app diff myapp
|
||||
|
||||
# History
|
||||
argocd app history myapp
|
||||
```
|
||||
@@ -0,0 +1,445 @@
|
||||
---
|
||||
name: helm-charts
|
||||
description: Create, manage, and deploy Helm charts for Kubernetes package management. Build reusable chart templates, manage releases, configure values, and use Helm repositories. Use when packaging Kubernetes applications or managing K8s deployments with Helm.
|
||||
license: MIT
|
||||
metadata:
|
||||
author: devops-skills
|
||||
version: "1.0"
|
||||
---
|
||||
|
||||
# Helm Charts
|
||||
|
||||
Package and deploy Kubernetes applications using Helm, the package manager for Kubernetes.
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
Use this skill when:
|
||||
- Creating reusable Kubernetes application packages
|
||||
- Deploying applications with configurable values
|
||||
- Managing Helm releases and upgrades
|
||||
- Using third-party Helm charts
|
||||
- Implementing chart versioning and repositories
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Helm 3.x installed
|
||||
- kubectl configured with cluster access
|
||||
- Basic Kubernetes knowledge
|
||||
|
||||
## Chart Structure
|
||||
|
||||
```
|
||||
mychart/
|
||||
├── Chart.yaml # Chart metadata
|
||||
├── values.yaml # Default configuration values
|
||||
├── charts/ # Chart dependencies
|
||||
├── templates/ # Kubernetes manifest templates
|
||||
│ ├── deployment.yaml
|
||||
│ ├── service.yaml
|
||||
│ ├── ingress.yaml
|
||||
│ ├── configmap.yaml
|
||||
│ ├── secret.yaml
|
||||
│ ├── _helpers.tpl # Template helpers
|
||||
│ ├── NOTES.txt # Post-install notes
|
||||
│ └── tests/
|
||||
│ └── test-connection.yaml
|
||||
└── .helmignore # Files to ignore
|
||||
```
|
||||
|
||||
## Chart.yaml
|
||||
|
||||
```yaml
|
||||
apiVersion: v2
|
||||
name: myapp
|
||||
description: A Helm chart for MyApp
|
||||
type: application
|
||||
version: 1.0.0
|
||||
appVersion: "2.0.0"
|
||||
keywords:
|
||||
- myapp
|
||||
- web
|
||||
maintainers:
|
||||
- name: DevOps Team
|
||||
email: devops@example.com
|
||||
dependencies:
|
||||
- name: postgresql
|
||||
version: "12.x.x"
|
||||
repository: "https://charts.bitnami.com/bitnami"
|
||||
condition: postgresql.enabled
|
||||
```
|
||||
|
||||
## values.yaml
|
||||
|
||||
```yaml
|
||||
replicaCount: 2
|
||||
|
||||
image:
|
||||
repository: myapp
|
||||
tag: "" # Defaults to appVersion
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 80
|
||||
|
||||
ingress:
|
||||
enabled: false
|
||||
className: nginx
|
||||
hosts:
|
||||
- host: myapp.example.com
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
tls: []
|
||||
|
||||
resources:
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 256Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
|
||||
postgresql:
|
||||
enabled: true
|
||||
auth:
|
||||
database: myapp
|
||||
```
|
||||
|
||||
## Templates
|
||||
|
||||
### Deployment Template
|
||||
|
||||
```yaml
|
||||
# templates/deployment.yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "myapp.fullname" . }}
|
||||
labels:
|
||||
{{- include "myapp.labels" . | nindent 4 }}
|
||||
spec:
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "myapp.selectorLabels" . | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "myapp.selectorLabels" . | nindent 8 }}
|
||||
spec:
|
||||
containers:
|
||||
- name: {{ .Chart.Name }}
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 8080
|
||||
{{- with .Values.resources }}
|
||||
resources:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
env:
|
||||
- name: DATABASE_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "myapp.fullname" . }}-secrets
|
||||
key: database-url
|
||||
```
|
||||
|
||||
### Helper Functions
|
||||
|
||||
```yaml
|
||||
# templates/_helpers.tpl
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "myapp.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
*/}}
|
||||
{{- define "myapp.fullname" -}}
|
||||
{{- if .Values.fullnameOverride }}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Common labels
|
||||
*/}}
|
||||
{{- define "myapp.labels" -}}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
|
||||
{{ include "myapp.selectorLabels" . }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Selector labels
|
||||
*/}}
|
||||
{{- define "myapp.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ include "myapp.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
```
|
||||
|
||||
### Conditional Resources
|
||||
|
||||
```yaml
|
||||
# templates/ingress.yaml
|
||||
{{- if .Values.ingress.enabled -}}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ include "myapp.fullname" . }}
|
||||
labels:
|
||||
{{- include "myapp.labels" . | nindent 4 }}
|
||||
{{- with .Values.ingress.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
ingressClassName: {{ .Values.ingress.className }}
|
||||
{{- if .Values.ingress.tls }}
|
||||
tls:
|
||||
{{- range .Values.ingress.tls }}
|
||||
- hosts:
|
||||
{{- range .hosts }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
secretName: {{ .secretName }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range .Values.ingress.hosts }}
|
||||
- host: {{ .host | quote }}
|
||||
http:
|
||||
paths:
|
||||
{{- range .paths }}
|
||||
- path: {{ .path }}
|
||||
pathType: {{ .pathType }}
|
||||
backend:
|
||||
service:
|
||||
name: {{ include "myapp.fullname" $ }}
|
||||
port:
|
||||
number: {{ $.Values.service.port }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
```
|
||||
|
||||
## Helm Commands
|
||||
|
||||
### Installing Charts
|
||||
|
||||
```bash
|
||||
# Install from local chart
|
||||
helm install myapp ./mychart
|
||||
|
||||
# Install with custom values
|
||||
helm install myapp ./mychart -f custom-values.yaml
|
||||
|
||||
# Install with value overrides
|
||||
helm install myapp ./mychart \
|
||||
--set replicaCount=3 \
|
||||
--set image.tag=2.0.0
|
||||
|
||||
# Install in specific namespace
|
||||
helm install myapp ./mychart -n production --create-namespace
|
||||
|
||||
# Dry run to preview
|
||||
helm install myapp ./mychart --dry-run --debug
|
||||
```
|
||||
|
||||
### Managing Releases
|
||||
|
||||
```bash
|
||||
# List releases
|
||||
helm list
|
||||
helm list -A # All namespaces
|
||||
|
||||
# Upgrade release
|
||||
helm upgrade myapp ./mychart
|
||||
helm upgrade myapp ./mychart -f new-values.yaml
|
||||
|
||||
# Rollback
|
||||
helm rollback myapp 1
|
||||
helm history myapp
|
||||
|
||||
# Uninstall
|
||||
helm uninstall myapp
|
||||
```
|
||||
|
||||
### Chart Development
|
||||
|
||||
```bash
|
||||
# Create new chart
|
||||
helm create mychart
|
||||
|
||||
# Lint chart
|
||||
helm lint ./mychart
|
||||
|
||||
# Template locally (debug)
|
||||
helm template myapp ./mychart
|
||||
|
||||
# Package chart
|
||||
helm package ./mychart
|
||||
|
||||
# Update dependencies
|
||||
helm dependency update ./mychart
|
||||
```
|
||||
|
||||
## Repositories
|
||||
|
||||
```bash
|
||||
# Add repository
|
||||
helm repo add bitnami https://charts.bitnami.com/bitnami
|
||||
|
||||
# Update repositories
|
||||
helm repo update
|
||||
|
||||
# Search charts
|
||||
helm search repo postgresql
|
||||
helm search hub prometheus
|
||||
|
||||
# Install from repo
|
||||
helm install postgres bitnami/postgresql
|
||||
|
||||
# Show chart info
|
||||
helm show values bitnami/postgresql
|
||||
```
|
||||
|
||||
## Advanced Features
|
||||
|
||||
### Hooks
|
||||
|
||||
```yaml
|
||||
# templates/pre-install-job.yaml
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: {{ include "myapp.fullname" . }}-migration
|
||||
annotations:
|
||||
"helm.sh/hook": pre-install,pre-upgrade
|
||||
"helm.sh/hook-weight": "-5"
|
||||
"helm.sh/hook-delete-policy": hook-succeeded
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: migrate
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||
command: ["./migrate.sh"]
|
||||
restartPolicy: Never
|
||||
```
|
||||
|
||||
### Tests
|
||||
|
||||
```yaml
|
||||
# templates/tests/test-connection.yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: "{{ include "myapp.fullname" . }}-test-connection"
|
||||
annotations:
|
||||
"helm.sh/hook": test
|
||||
spec:
|
||||
containers:
|
||||
- name: wget
|
||||
image: busybox
|
||||
command: ['wget']
|
||||
args: ['{{ include "myapp.fullname" . }}:{{ .Values.service.port }}']
|
||||
restartPolicy: Never
|
||||
```
|
||||
|
||||
```bash
|
||||
# Run tests
|
||||
helm test myapp
|
||||
```
|
||||
|
||||
### Library Charts
|
||||
|
||||
```yaml
|
||||
# Chart.yaml
|
||||
apiVersion: v2
|
||||
name: mylib
|
||||
type: library
|
||||
version: 1.0.0
|
||||
```
|
||||
|
||||
```yaml
|
||||
# Using library chart
|
||||
dependencies:
|
||||
- name: mylib
|
||||
version: "1.x.x"
|
||||
repository: "file://../mylib"
|
||||
```
|
||||
|
||||
## OCI Registry Support
|
||||
|
||||
```bash
|
||||
# Login to registry
|
||||
helm registry login registry.example.com
|
||||
|
||||
# Push chart to OCI registry
|
||||
helm push mychart-1.0.0.tgz oci://registry.example.com/charts
|
||||
|
||||
# Pull from OCI registry
|
||||
helm pull oci://registry.example.com/charts/mychart --version 1.0.0
|
||||
|
||||
# Install from OCI
|
||||
helm install myapp oci://registry.example.com/charts/mychart
|
||||
```
|
||||
|
||||
## Common Issues
|
||||
|
||||
### Issue: YAML Indentation Errors
|
||||
**Problem**: Template renders with wrong indentation
|
||||
**Solution**: Use `nindent` helper function
|
||||
|
||||
```yaml
|
||||
{{- toYaml .Values.resources | nindent 12 }}
|
||||
```
|
||||
|
||||
### Issue: Values Not Applying
|
||||
**Problem**: Custom values not reflected
|
||||
**Solution**: Check value paths, use `--debug` flag
|
||||
|
||||
```bash
|
||||
helm template myapp ./mychart --debug
|
||||
```
|
||||
|
||||
### Issue: Dependency Errors
|
||||
**Problem**: Chart dependencies not found
|
||||
**Solution**: Run `helm dependency update`
|
||||
|
||||
### Issue: Release Already Exists
|
||||
**Problem**: Cannot install, release exists
|
||||
**Solution**: Use `helm upgrade --install`
|
||||
|
||||
```bash
|
||||
helm upgrade --install myapp ./mychart
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Use semantic versioning for charts
|
||||
- Provide comprehensive default values
|
||||
- Document all values in values.yaml with comments
|
||||
- Use helper templates for repeated patterns
|
||||
- Implement chart tests
|
||||
- Use .helmignore to exclude unnecessary files
|
||||
- Pin dependency versions
|
||||
- Use `helm lint` in CI pipelines
|
||||
|
||||
## Related Skills
|
||||
|
||||
- [kubernetes-ops](../kubernetes-ops/) - K8s fundamentals
|
||||
- [argocd-gitops](../argocd-gitops/) - GitOps with Helm
|
||||
- [kustomize](../kustomize/) - Alternative templating
|
||||
@@ -0,0 +1,121 @@
|
||||
# Helm Commands Reference
|
||||
|
||||
## Chart Management
|
||||
|
||||
```bash
|
||||
# Create new chart
|
||||
helm create mychart
|
||||
|
||||
# Lint chart
|
||||
helm lint mychart/
|
||||
|
||||
# Package chart
|
||||
helm package mychart/
|
||||
|
||||
# Template (render without installing)
|
||||
helm template myrelease mychart/ --values values.yaml
|
||||
```
|
||||
|
||||
## Repository
|
||||
|
||||
```bash
|
||||
# Add repo
|
||||
helm repo add bitnami https://charts.bitnami.com/bitnami
|
||||
helm repo add stable https://charts.helm.sh/stable
|
||||
|
||||
# Update repos
|
||||
helm repo update
|
||||
|
||||
# Search
|
||||
helm search repo nginx
|
||||
helm search hub nginx
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
# Install
|
||||
helm install myrelease mychart/
|
||||
helm install myrelease bitnami/nginx --namespace prod --create-namespace
|
||||
|
||||
# With values
|
||||
helm install myrelease mychart/ -f values.yaml
|
||||
helm install myrelease mychart/ --set image.tag=v1.0
|
||||
|
||||
# Dry run
|
||||
helm install myrelease mychart/ --dry-run --debug
|
||||
|
||||
# Wait for completion
|
||||
helm install myrelease mychart/ --wait --timeout 5m
|
||||
```
|
||||
|
||||
## Upgrade & Rollback
|
||||
|
||||
```bash
|
||||
# Upgrade
|
||||
helm upgrade myrelease mychart/ -f values.yaml
|
||||
helm upgrade --install myrelease mychart/ # Install or upgrade
|
||||
|
||||
# Rollback
|
||||
helm rollback myrelease 1 # Rollback to revision 1
|
||||
helm rollback myrelease # Previous revision
|
||||
|
||||
# History
|
||||
helm history myrelease
|
||||
```
|
||||
|
||||
## Management
|
||||
|
||||
```bash
|
||||
# List releases
|
||||
helm list
|
||||
helm list -A # All namespaces
|
||||
helm list --pending
|
||||
|
||||
# Get info
|
||||
helm get values myrelease
|
||||
helm get manifest myrelease
|
||||
helm get all myrelease
|
||||
|
||||
# Status
|
||||
helm status myrelease
|
||||
|
||||
# Uninstall
|
||||
helm uninstall myrelease
|
||||
helm uninstall myrelease --keep-history
|
||||
```
|
||||
|
||||
## Chart Structure
|
||||
|
||||
```
|
||||
mychart/
|
||||
├── Chart.yaml # Chart metadata
|
||||
├── values.yaml # Default values
|
||||
├── charts/ # Dependencies
|
||||
├── templates/
|
||||
│ ├── NOTES.txt # Post-install notes
|
||||
│ ├── _helpers.tpl # Template helpers
|
||||
│ ├── deployment.yaml
|
||||
│ ├── service.yaml
|
||||
│ └── ingress.yaml
|
||||
└── .helmignore
|
||||
```
|
||||
|
||||
## Template Functions
|
||||
|
||||
```yaml
|
||||
# Built-in functions
|
||||
{{ .Values.image.tag | default "latest" }}
|
||||
{{ .Release.Name | upper }}
|
||||
{{ include "mychart.fullname" . }}
|
||||
|
||||
# Conditionals
|
||||
{{- if .Values.ingress.enabled }}
|
||||
# ingress config
|
||||
{{- end }}
|
||||
|
||||
# Loops
|
||||
{{- range .Values.hosts }}
|
||||
- host: {{ . }}
|
||||
{{- end }}
|
||||
```
|
||||
@@ -0,0 +1,516 @@
|
||||
---
|
||||
name: kubernetes-ops
|
||||
description: Deploy, scale, and manage Kubernetes workloads. Create deployments, services, and configurations, manage cluster resources, troubleshoot pods, and implement production-ready Kubernetes patterns. Use when working with Kubernetes clusters, K8s deployments, or container orchestration.
|
||||
license: MIT
|
||||
metadata:
|
||||
author: devops-skills
|
||||
version: "1.0"
|
||||
---
|
||||
|
||||
# Kubernetes Operations
|
||||
|
||||
Deploy and manage containerized applications on Kubernetes clusters.
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
Use this skill when:
|
||||
- Deploying applications to Kubernetes
|
||||
- Managing pods, deployments, and services
|
||||
- Configuring resource limits and scaling
|
||||
- Troubleshooting Kubernetes workloads
|
||||
- Setting up networking and ingress
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- kubectl installed and configured
|
||||
- Access to a Kubernetes cluster
|
||||
- Basic understanding of containers
|
||||
|
||||
## Core Resources
|
||||
|
||||
### Deployment
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: myapp
|
||||
labels:
|
||||
app: myapp
|
||||
spec:
|
||||
replicas: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app: myapp
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: myapp
|
||||
spec:
|
||||
containers:
|
||||
- name: myapp
|
||||
image: myapp:1.0.0
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
resources:
|
||||
requests:
|
||||
memory: "128Mi"
|
||||
cpu: "100m"
|
||||
limits:
|
||||
memory: "256Mi"
|
||||
cpu: "500m"
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 8080
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 10
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /ready
|
||||
port: 8080
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
env:
|
||||
- name: DATABASE_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: myapp-secrets
|
||||
key: database-url
|
||||
```
|
||||
|
||||
### Service
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: myapp
|
||||
spec:
|
||||
selector:
|
||||
app: myapp
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 8080
|
||||
type: ClusterIP
|
||||
---
|
||||
# LoadBalancer for external access
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: myapp-external
|
||||
spec:
|
||||
selector:
|
||||
app: myapp
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 8080
|
||||
type: LoadBalancer
|
||||
```
|
||||
|
||||
### Ingress
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: myapp
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/rewrite-target: /
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
tls:
|
||||
- hosts:
|
||||
- myapp.example.com
|
||||
secretName: myapp-tls
|
||||
rules:
|
||||
- host: myapp.example.com
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: myapp
|
||||
port:
|
||||
number: 80
|
||||
```
|
||||
|
||||
## Configuration Management
|
||||
|
||||
### ConfigMap
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: myapp-config
|
||||
data:
|
||||
config.yaml: |
|
||||
server:
|
||||
port: 8080
|
||||
logging:
|
||||
level: info
|
||||
APP_ENV: production
|
||||
```
|
||||
|
||||
```yaml
|
||||
# Using ConfigMap
|
||||
containers:
|
||||
- name: myapp
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: myapp-config
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /etc/config
|
||||
volumes:
|
||||
- name: config
|
||||
configMap:
|
||||
name: myapp-config
|
||||
```
|
||||
|
||||
### Secret
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: myapp-secrets
|
||||
type: Opaque
|
||||
stringData:
|
||||
database-url: postgres://user:pass@host:5432/db
|
||||
api-key: secret-key-value
|
||||
```
|
||||
|
||||
```bash
|
||||
# Create secret from command line
|
||||
kubectl create secret generic myapp-secrets \
|
||||
--from-literal=database-url='postgres://...' \
|
||||
--from-file=tls.crt=cert.pem
|
||||
```
|
||||
|
||||
## kubectl Commands
|
||||
|
||||
### Resource Management
|
||||
|
||||
```bash
|
||||
# Apply configuration
|
||||
kubectl apply -f deployment.yaml
|
||||
|
||||
# Get resources
|
||||
kubectl get pods
|
||||
kubectl get deployments
|
||||
kubectl get services
|
||||
kubectl get all -n myapp
|
||||
|
||||
# Describe resource
|
||||
kubectl describe pod myapp-xxx
|
||||
|
||||
# Delete resource
|
||||
kubectl delete -f deployment.yaml
|
||||
kubectl delete pod myapp-xxx
|
||||
|
||||
# Edit resource
|
||||
kubectl edit deployment myapp
|
||||
```
|
||||
|
||||
### Debugging
|
||||
|
||||
```bash
|
||||
# View logs
|
||||
kubectl logs myapp-xxx
|
||||
kubectl logs -f myapp-xxx --tail=100
|
||||
kubectl logs myapp-xxx -c sidecar # specific container
|
||||
|
||||
# Execute command
|
||||
kubectl exec -it myapp-xxx -- /bin/sh
|
||||
|
||||
# Port forward
|
||||
kubectl port-forward svc/myapp 8080:80
|
||||
kubectl port-forward pod/myapp-xxx 8080:8080
|
||||
|
||||
# View events
|
||||
kubectl get events --sort-by='.lastTimestamp'
|
||||
|
||||
# Debug pod
|
||||
kubectl debug myapp-xxx -it --image=busybox
|
||||
```
|
||||
|
||||
### Scaling
|
||||
|
||||
```bash
|
||||
# Manual scaling
|
||||
kubectl scale deployment myapp --replicas=5
|
||||
|
||||
# Autoscaling
|
||||
kubectl autoscale deployment myapp \
|
||||
--min=2 --max=10 \
|
||||
--cpu-percent=80
|
||||
```
|
||||
|
||||
## Horizontal Pod Autoscaler
|
||||
|
||||
```yaml
|
||||
apiVersion: autoscaling/v2
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: myapp
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: myapp
|
||||
minReplicas: 2
|
||||
maxReplicas: 10
|
||||
metrics:
|
||||
- type: Resource
|
||||
resource:
|
||||
name: cpu
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: 80
|
||||
- type: Resource
|
||||
resource:
|
||||
name: memory
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: 80
|
||||
```
|
||||
|
||||
## Persistent Storage
|
||||
|
||||
### PersistentVolumeClaim
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: myapp-data
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: standard
|
||||
resources:
|
||||
requests:
|
||||
storage: 10Gi
|
||||
---
|
||||
# Using PVC
|
||||
containers:
|
||||
- name: myapp
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /data
|
||||
volumes:
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: myapp-data
|
||||
```
|
||||
|
||||
## StatefulSet
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: postgres
|
||||
spec:
|
||||
serviceName: postgres
|
||||
replicas: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app: postgres
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: postgres
|
||||
spec:
|
||||
containers:
|
||||
- name: postgres
|
||||
image: postgres:15
|
||||
ports:
|
||||
- containerPort: 5432
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /var/lib/postgresql/data
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: data
|
||||
spec:
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
resources:
|
||||
requests:
|
||||
storage: 10Gi
|
||||
```
|
||||
|
||||
## Jobs and CronJobs
|
||||
|
||||
### Job
|
||||
|
||||
```yaml
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: migration
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: migrate
|
||||
image: myapp:1.0.0
|
||||
command: ["./migrate.sh"]
|
||||
restartPolicy: Never
|
||||
backoffLimit: 3
|
||||
```
|
||||
|
||||
### CronJob
|
||||
|
||||
```yaml
|
||||
apiVersion: batch/v1
|
||||
kind: CronJob
|
||||
metadata:
|
||||
name: backup
|
||||
spec:
|
||||
schedule: "0 2 * * *"
|
||||
jobTemplate:
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: backup
|
||||
image: backup-tool:latest
|
||||
command: ["./backup.sh"]
|
||||
restartPolicy: OnFailure
|
||||
```
|
||||
|
||||
## Network Policies
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: myapp-network-policy
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app: myapp
|
||||
policyTypes:
|
||||
- Ingress
|
||||
- Egress
|
||||
ingress:
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app: frontend
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 8080
|
||||
egress:
|
||||
- to:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app: database
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 5432
|
||||
```
|
||||
|
||||
## Resource Quotas
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ResourceQuota
|
||||
metadata:
|
||||
name: myapp-quota
|
||||
namespace: myapp
|
||||
spec:
|
||||
hard:
|
||||
requests.cpu: "10"
|
||||
requests.memory: 20Gi
|
||||
limits.cpu: "20"
|
||||
limits.memory: 40Gi
|
||||
pods: "20"
|
||||
```
|
||||
|
||||
## Rolling Updates
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
strategy:
|
||||
type: RollingUpdate
|
||||
rollingUpdate:
|
||||
maxSurge: 1
|
||||
maxUnavailable: 0
|
||||
```
|
||||
|
||||
```bash
|
||||
# Update image
|
||||
kubectl set image deployment/myapp myapp=myapp:2.0.0
|
||||
|
||||
# Check rollout status
|
||||
kubectl rollout status deployment/myapp
|
||||
|
||||
# View history
|
||||
kubectl rollout history deployment/myapp
|
||||
|
||||
# Rollback
|
||||
kubectl rollout undo deployment/myapp
|
||||
kubectl rollout undo deployment/myapp --to-revision=2
|
||||
```
|
||||
|
||||
## Common Issues
|
||||
|
||||
### Issue: Pod Stuck in Pending
|
||||
**Problem**: Pod won't start
|
||||
**Solution**: Check resource availability, node selector, PVC binding
|
||||
|
||||
```bash
|
||||
kubectl describe pod myapp-xxx
|
||||
kubectl get events
|
||||
```
|
||||
|
||||
### Issue: CrashLoopBackOff
|
||||
**Problem**: Container keeps restarting
|
||||
**Solution**: Check logs, verify entrypoint, check probes
|
||||
|
||||
```bash
|
||||
kubectl logs myapp-xxx --previous
|
||||
kubectl describe pod myapp-xxx
|
||||
```
|
||||
|
||||
### Issue: Service Not Accessible
|
||||
**Problem**: Cannot connect to service
|
||||
**Solution**: Check selector labels, verify endpoints exist
|
||||
|
||||
```bash
|
||||
kubectl get endpoints myapp
|
||||
kubectl describe svc myapp
|
||||
```
|
||||
|
||||
### Issue: Image Pull Error
|
||||
**Problem**: ImagePullBackOff
|
||||
**Solution**: Check image name, verify registry credentials
|
||||
|
||||
```bash
|
||||
kubectl create secret docker-registry regcred \
|
||||
--docker-server=registry.example.com \
|
||||
--docker-username=user \
|
||||
--docker-password=pass
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Always set resource requests and limits
|
||||
- Implement liveness and readiness probes
|
||||
- Use namespaces for isolation
|
||||
- Apply network policies for security
|
||||
- Use ConfigMaps and Secrets for configuration
|
||||
- Implement pod disruption budgets for availability
|
||||
- Use labels consistently for organization
|
||||
- Enable RBAC for access control
|
||||
|
||||
## Related Skills
|
||||
|
||||
- [helm-charts](../helm-charts/) - Package management
|
||||
- [argocd-gitops](../argocd-gitops/) - GitOps deployments
|
||||
- [kubernetes-hardening](../../../security/hardening/kubernetes-hardening/) - Security
|
||||
@@ -0,0 +1,166 @@
|
||||
# Production-Ready Deployment Template
|
||||
# Customize values marked with <REPLACE>
|
||||
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: <APP_NAME>
|
||||
labels:
|
||||
app: <APP_NAME>
|
||||
version: v1
|
||||
spec:
|
||||
replicas: 3
|
||||
strategy:
|
||||
type: RollingUpdate
|
||||
rollingUpdate:
|
||||
maxSurge: 1
|
||||
maxUnavailable: 0
|
||||
selector:
|
||||
matchLabels:
|
||||
app: <APP_NAME>
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: <APP_NAME>
|
||||
version: v1
|
||||
annotations:
|
||||
prometheus.io/scrape: "true"
|
||||
prometheus.io/port: "8080"
|
||||
prometheus.io/path: "/metrics"
|
||||
spec:
|
||||
serviceAccountName: <APP_NAME>
|
||||
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1000
|
||||
fsGroup: 1000
|
||||
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- weight: 100
|
||||
podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app: <APP_NAME>
|
||||
topologyKey: kubernetes.io/hostname
|
||||
|
||||
containers:
|
||||
- name: <APP_NAME>
|
||||
image: <IMAGE>:<TAG>
|
||||
imagePullPolicy: Always
|
||||
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 8080
|
||||
protocol: TCP
|
||||
|
||||
env:
|
||||
- name: POD_NAME
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.name
|
||||
- name: POD_NAMESPACE
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: <APP_NAME>-config
|
||||
- secretRef:
|
||||
name: <APP_NAME>-secrets
|
||||
|
||||
resources:
|
||||
requests:
|
||||
memory: "256Mi"
|
||||
cpu: "250m"
|
||||
limits:
|
||||
memory: "512Mi"
|
||||
|
||||
securityContext:
|
||||
readOnlyRootFilesystem: true
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: http
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 3
|
||||
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /ready
|
||||
port: http
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 3
|
||||
failureThreshold: 3
|
||||
|
||||
volumeMounts:
|
||||
- name: tmp
|
||||
mountPath: /tmp
|
||||
- name: cache
|
||||
mountPath: /var/cache
|
||||
|
||||
volumes:
|
||||
- name: tmp
|
||||
emptyDir: {}
|
||||
- name: cache
|
||||
emptyDir: {}
|
||||
|
||||
terminationGracePeriodSeconds: 30
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: <APP_NAME>
|
||||
labels:
|
||||
app: <APP_NAME>
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
app: <APP_NAME>
|
||||
|
||||
---
|
||||
apiVersion: autoscaling/v2
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: <APP_NAME>
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: <APP_NAME>
|
||||
minReplicas: 3
|
||||
maxReplicas: 10
|
||||
metrics:
|
||||
- type: Resource
|
||||
resource:
|
||||
name: cpu
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: 70
|
||||
|
||||
---
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: <APP_NAME>
|
||||
spec:
|
||||
minAvailable: 2
|
||||
selector:
|
||||
matchLabels:
|
||||
app: <APP_NAME>
|
||||
@@ -0,0 +1,187 @@
|
||||
# Kubernetes Best Practices
|
||||
|
||||
## Resource Management
|
||||
|
||||
### Always Set Resource Requests and Limits
|
||||
```yaml
|
||||
resources:
|
||||
requests:
|
||||
memory: "256Mi"
|
||||
cpu: "250m"
|
||||
limits:
|
||||
memory: "512Mi"
|
||||
cpu: "500m"
|
||||
```
|
||||
|
||||
**Guidelines:**
|
||||
- Requests = guaranteed resources
|
||||
- Limits = maximum resources
|
||||
- Set requests based on normal usage
|
||||
- Set limits based on peak usage
|
||||
- Memory limit = 2x request is common
|
||||
- Avoid CPU limits in most cases (causes throttling)
|
||||
|
||||
### Use Horizontal Pod Autoscaler
|
||||
```yaml
|
||||
apiVersion: autoscaling/v2
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: myapp-hpa
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: myapp
|
||||
minReplicas: 2
|
||||
maxReplicas: 10
|
||||
metrics:
|
||||
- type: Resource
|
||||
resource:
|
||||
name: cpu
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: 70
|
||||
```
|
||||
|
||||
## Pod Configuration
|
||||
|
||||
### Use Liveness and Readiness Probes
|
||||
```yaml
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 8080
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
failureThreshold: 3
|
||||
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /ready
|
||||
port: 8080
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
```
|
||||
|
||||
### Configure Pod Disruption Budgets
|
||||
```yaml
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: myapp-pdb
|
||||
spec:
|
||||
minAvailable: 2
|
||||
selector:
|
||||
matchLabels:
|
||||
app: myapp
|
||||
```
|
||||
|
||||
### Use Anti-Affinity for High Availability
|
||||
```yaml
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- weight: 100
|
||||
podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app: myapp
|
||||
topologyKey: kubernetes.io/hostname
|
||||
```
|
||||
|
||||
## Security
|
||||
|
||||
### Run as Non-Root
|
||||
```yaml
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1000
|
||||
runAsGroup: 1000
|
||||
fsGroup: 1000
|
||||
```
|
||||
|
||||
### Read-Only Root Filesystem
|
||||
```yaml
|
||||
securityContext:
|
||||
readOnlyRootFilesystem: true
|
||||
volumeMounts:
|
||||
- name: tmp
|
||||
mountPath: /tmp
|
||||
volumes:
|
||||
- name: tmp
|
||||
emptyDir: {}
|
||||
```
|
||||
|
||||
### Drop All Capabilities
|
||||
```yaml
|
||||
securityContext:
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
```
|
||||
|
||||
## Networking
|
||||
|
||||
### Use Network Policies
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: deny-all
|
||||
spec:
|
||||
podSelector: {}
|
||||
policyTypes:
|
||||
- Ingress
|
||||
- Egress
|
||||
```
|
||||
|
||||
### Service Mesh for mTLS
|
||||
- Istio, Linkerd, or Consul Connect
|
||||
- Automatic encryption between services
|
||||
- Traffic management capabilities
|
||||
|
||||
## Configuration Management
|
||||
|
||||
### Use ConfigMaps for Configuration
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: app-config
|
||||
data:
|
||||
LOG_LEVEL: "info"
|
||||
DATABASE_HOST: "postgres.default.svc"
|
||||
```
|
||||
|
||||
### Use Secrets for Sensitive Data
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: app-secrets
|
||||
type: Opaque
|
||||
stringData:
|
||||
DATABASE_PASSWORD: "secret123"
|
||||
```
|
||||
|
||||
### External Secrets for Production
|
||||
- Use External Secrets Operator
|
||||
- Integrate with Vault, AWS Secrets Manager, etc.
|
||||
- Never commit secrets to git
|
||||
|
||||
## Observability
|
||||
|
||||
### Structured Logging
|
||||
- Output JSON logs
|
||||
- Include correlation IDs
|
||||
- Use consistent field names
|
||||
|
||||
### Metrics
|
||||
- Expose Prometheus metrics
|
||||
- Use standard naming conventions
|
||||
- Include SLI metrics
|
||||
|
||||
### Distributed Tracing
|
||||
- Implement OpenTelemetry
|
||||
- Propagate trace context
|
||||
- Sample appropriately
|
||||
@@ -0,0 +1,165 @@
|
||||
# Kubernetes Troubleshooting Guide
|
||||
|
||||
## Common Issues and Solutions
|
||||
|
||||
### Pod Issues
|
||||
|
||||
#### Pod Stuck in Pending
|
||||
```bash
|
||||
# Check events
|
||||
kubectl describe pod <pod-name> -n <namespace>
|
||||
|
||||
# Common causes:
|
||||
# - Insufficient resources
|
||||
kubectl describe nodes | grep -A 5 "Allocated resources"
|
||||
|
||||
# - No matching nodes (taints/tolerations)
|
||||
kubectl get nodes -o json | jq '.items[].spec.taints'
|
||||
|
||||
# - PVC not bound
|
||||
kubectl get pvc -n <namespace>
|
||||
```
|
||||
|
||||
#### Pod in CrashLoopBackOff
|
||||
```bash
|
||||
# Check logs
|
||||
kubectl logs <pod-name> -n <namespace> --previous
|
||||
|
||||
# Check container exit code
|
||||
kubectl get pod <pod-name> -n <namespace> -o jsonpath='{.status.containerStatuses[0].lastState.terminated.exitCode}'
|
||||
|
||||
# Common exit codes:
|
||||
# 0 - Success (check livenessProbe)
|
||||
# 1 - Application error
|
||||
# 137 - OOMKilled (increase memory)
|
||||
# 139 - Segmentation fault
|
||||
# 143 - SIGTERM received
|
||||
```
|
||||
|
||||
#### Pod in ImagePullBackOff
|
||||
```bash
|
||||
# Check image name
|
||||
kubectl get pod <pod-name> -n <namespace> -o jsonpath='{.spec.containers[0].image}'
|
||||
|
||||
# Verify image exists
|
||||
docker pull <image>
|
||||
|
||||
# Check imagePullSecrets
|
||||
kubectl get pod <pod-name> -n <namespace> -o jsonpath='{.spec.imagePullSecrets}'
|
||||
kubectl get secret <secret-name> -n <namespace> -o jsonpath='{.data.\.dockerconfigjson}' | base64 -d
|
||||
```
|
||||
|
||||
### Service Issues
|
||||
|
||||
#### Service Not Accessible
|
||||
```bash
|
||||
# Verify endpoints exist
|
||||
kubectl get endpoints <service-name> -n <namespace>
|
||||
|
||||
# Check selector matches pod labels
|
||||
kubectl get svc <service-name> -n <namespace> -o jsonpath='{.spec.selector}'
|
||||
kubectl get pods -n <namespace> --show-labels
|
||||
|
||||
# Test from within cluster
|
||||
kubectl run debug --rm -it --image=busybox -- wget -qO- http://<service>.<namespace>.svc.cluster.local
|
||||
```
|
||||
|
||||
#### DNS Resolution Issues
|
||||
```bash
|
||||
# Test DNS from pod
|
||||
kubectl run dns-test --rm -it --image=busybox -- nslookup kubernetes.default
|
||||
|
||||
# Check CoreDNS pods
|
||||
kubectl get pods -n kube-system -l k8s-app=kube-dns
|
||||
|
||||
# Check CoreDNS logs
|
||||
kubectl logs -n kube-system -l k8s-app=kube-dns
|
||||
```
|
||||
|
||||
### Node Issues
|
||||
|
||||
#### Node NotReady
|
||||
```bash
|
||||
# Check node conditions
|
||||
kubectl describe node <node-name> | grep -A 20 Conditions
|
||||
|
||||
# Check kubelet status
|
||||
systemctl status kubelet
|
||||
|
||||
# Check kubelet logs
|
||||
journalctl -u kubelet -f
|
||||
|
||||
# Common causes:
|
||||
# - Disk pressure
|
||||
# - Memory pressure
|
||||
# - Network issues
|
||||
# - Container runtime issues
|
||||
```
|
||||
|
||||
#### Node Disk Pressure
|
||||
```bash
|
||||
# Check disk usage
|
||||
kubectl describe node <node-name> | grep -A 3 "Allocated resources"
|
||||
|
||||
# Cleanup unused images
|
||||
docker system prune -af
|
||||
|
||||
# Check for large logs
|
||||
du -sh /var/log/containers/*
|
||||
```
|
||||
|
||||
### Networking Issues
|
||||
|
||||
#### Pod-to-Pod Communication Fails
|
||||
```bash
|
||||
# Test connectivity
|
||||
kubectl exec <pod-a> -- ping <pod-b-ip>
|
||||
|
||||
# Check network policies
|
||||
kubectl get networkpolicies -n <namespace>
|
||||
|
||||
# Verify CNI plugin
|
||||
kubectl get pods -n kube-system | grep -E "calico|weave|flannel|cilium"
|
||||
```
|
||||
|
||||
### Storage Issues
|
||||
|
||||
#### PVC Stuck in Pending
|
||||
```bash
|
||||
# Check PVC events
|
||||
kubectl describe pvc <pvc-name> -n <namespace>
|
||||
|
||||
# Verify StorageClass exists
|
||||
kubectl get storageclass
|
||||
|
||||
# Check provisioner pods
|
||||
kubectl get pods -n kube-system | grep provisioner
|
||||
```
|
||||
|
||||
## Diagnostic Commands Cheat Sheet
|
||||
|
||||
```bash
|
||||
# Cluster overview
|
||||
kubectl cluster-info
|
||||
kubectl get componentstatuses
|
||||
|
||||
# Resource usage
|
||||
kubectl top nodes
|
||||
kubectl top pods -n <namespace>
|
||||
|
||||
# Events
|
||||
kubectl get events -n <namespace> --sort-by='.lastTimestamp'
|
||||
|
||||
# Logs
|
||||
kubectl logs -f <pod> -n <namespace>
|
||||
kubectl logs -f <pod> -n <namespace> --all-containers
|
||||
|
||||
# Exec into pod
|
||||
kubectl exec -it <pod> -n <namespace> -- /bin/sh
|
||||
|
||||
# Port forward
|
||||
kubectl port-forward <pod> 8080:80 -n <namespace>
|
||||
|
||||
# Copy files
|
||||
kubectl cp <namespace>/<pod>:/path/to/file ./local-file
|
||||
```
|
||||
@@ -0,0 +1,78 @@
|
||||
#!/bin/bash
|
||||
# Kubernetes Cluster Health Check Script
|
||||
# Usage: ./cluster-health-check.sh [namespace]
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
NAMESPACE="${1:-default}"
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
echo "========================================="
|
||||
echo "Kubernetes Cluster Health Check"
|
||||
echo "========================================="
|
||||
echo ""
|
||||
|
||||
# Check cluster connectivity
|
||||
echo -n "Checking cluster connectivity... "
|
||||
if kubectl cluster-info &>/dev/null; then
|
||||
echo -e "${GREEN}OK${NC}"
|
||||
else
|
||||
echo -e "${RED}FAILED${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Node status
|
||||
echo ""
|
||||
echo "Node Status:"
|
||||
echo "------------"
|
||||
kubectl get nodes -o wide
|
||||
|
||||
# Check for NotReady nodes
|
||||
NOT_READY=$(kubectl get nodes --no-headers | grep -v " Ready" | wc -l)
|
||||
if [ "$NOT_READY" -gt 0 ]; then
|
||||
echo -e "${RED}WARNING: $NOT_READY node(s) not ready${NC}"
|
||||
fi
|
||||
|
||||
# Pod status in namespace
|
||||
echo ""
|
||||
echo "Pod Status in namespace '$NAMESPACE':"
|
||||
echo "--------------------------------------"
|
||||
kubectl get pods -n "$NAMESPACE" -o wide
|
||||
|
||||
# Check for failed pods
|
||||
FAILED_PODS=$(kubectl get pods -n "$NAMESPACE" --no-headers | grep -E "Error|CrashLoopBackOff|ImagePullBackOff" | wc -l)
|
||||
if [ "$FAILED_PODS" -gt 0 ]; then
|
||||
echo -e "${RED}WARNING: $FAILED_PODS pod(s) in error state${NC}"
|
||||
fi
|
||||
|
||||
# Resource usage
|
||||
echo ""
|
||||
echo "Resource Usage:"
|
||||
echo "---------------"
|
||||
kubectl top nodes 2>/dev/null || echo "Metrics server not available"
|
||||
|
||||
# Recent events
|
||||
echo ""
|
||||
echo "Recent Warning Events:"
|
||||
echo "----------------------"
|
||||
kubectl get events -n "$NAMESPACE" --field-selector type=Warning --sort-by='.lastTimestamp' | tail -10
|
||||
|
||||
# PVC status
|
||||
echo ""
|
||||
echo "PersistentVolumeClaim Status:"
|
||||
echo "-----------------------------"
|
||||
kubectl get pvc -n "$NAMESPACE" 2>/dev/null || echo "No PVCs found"
|
||||
|
||||
# Service status
|
||||
echo ""
|
||||
echo "Services:"
|
||||
echo "---------"
|
||||
kubectl get svc -n "$NAMESPACE"
|
||||
|
||||
echo ""
|
||||
echo "========================================="
|
||||
echo "Health check complete"
|
||||
echo "========================================="
|
||||
@@ -0,0 +1,75 @@
|
||||
#!/bin/bash
|
||||
# Kubernetes Namespace Cleanup Script
|
||||
# Removes completed jobs, failed pods, and unused resources
|
||||
# Usage: ./namespace-cleanup.sh <namespace> [--dry-run]
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
NAMESPACE="${1:-}"
|
||||
DRY_RUN="${2:-}"
|
||||
|
||||
if [ -z "$NAMESPACE" ]; then
|
||||
echo "Usage: $0 <namespace> [--dry-run]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$DRY_RUN" == "--dry-run" ]; then
|
||||
echo "DRY RUN MODE - No changes will be made"
|
||||
DELETE_CMD="echo [DRY RUN] Would delete:"
|
||||
else
|
||||
DELETE_CMD="kubectl delete"
|
||||
fi
|
||||
|
||||
echo "========================================="
|
||||
echo "Namespace Cleanup: $NAMESPACE"
|
||||
echo "========================================="
|
||||
echo ""
|
||||
|
||||
# Delete completed jobs
|
||||
echo "Cleaning up completed Jobs..."
|
||||
COMPLETED_JOBS=$(kubectl get jobs -n "$NAMESPACE" -o jsonpath='{.items[?(@.status.succeeded==1)].metadata.name}' 2>/dev/null)
|
||||
if [ -n "$COMPLETED_JOBS" ]; then
|
||||
for job in $COMPLETED_JOBS; do
|
||||
$DELETE_CMD job "$job" -n "$NAMESPACE" 2>/dev/null || true
|
||||
done
|
||||
else
|
||||
echo "No completed jobs found"
|
||||
fi
|
||||
|
||||
# Delete failed pods
|
||||
echo ""
|
||||
echo "Cleaning up failed Pods..."
|
||||
FAILED_PODS=$(kubectl get pods -n "$NAMESPACE" --field-selector status.phase=Failed -o name 2>/dev/null)
|
||||
if [ -n "$FAILED_PODS" ]; then
|
||||
for pod in $FAILED_PODS; do
|
||||
$DELETE_CMD "$pod" -n "$NAMESPACE" 2>/dev/null || true
|
||||
done
|
||||
else
|
||||
echo "No failed pods found"
|
||||
fi
|
||||
|
||||
# Delete evicted pods
|
||||
echo ""
|
||||
echo "Cleaning up evicted Pods..."
|
||||
EVICTED_PODS=$(kubectl get pods -n "$NAMESPACE" -o json | jq -r '.items[] | select(.status.reason=="Evicted") | .metadata.name' 2>/dev/null)
|
||||
if [ -n "$EVICTED_PODS" ]; then
|
||||
for pod in $EVICTED_PODS; do
|
||||
$DELETE_CMD pod "$pod" -n "$NAMESPACE" 2>/dev/null || true
|
||||
done
|
||||
else
|
||||
echo "No evicted pods found"
|
||||
fi
|
||||
|
||||
# Delete orphaned ReplicaSets (0 replicas, no owner)
|
||||
echo ""
|
||||
echo "Cleaning up orphaned ReplicaSets..."
|
||||
kubectl get rs -n "$NAMESPACE" -o json | jq -r '.items[] | select(.spec.replicas==0) | .metadata.name' 2>/dev/null | while read rs; do
|
||||
if [ -n "$rs" ]; then
|
||||
$DELETE_CMD rs "$rs" -n "$NAMESPACE" 2>/dev/null || true
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "========================================="
|
||||
echo "Cleanup complete"
|
||||
echo "========================================="
|
||||
@@ -0,0 +1,71 @@
|
||||
#!/bin/bash
|
||||
# Kubernetes Pod Debugging Script
|
||||
# Usage: ./pod-debug.sh <pod-name> [namespace]
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
POD_NAME="${1:-}"
|
||||
NAMESPACE="${2:-default}"
|
||||
|
||||
if [ -z "$POD_NAME" ]; then
|
||||
echo "Usage: $0 <pod-name> [namespace]"
|
||||
echo ""
|
||||
echo "Available pods in namespace '$NAMESPACE':"
|
||||
kubectl get pods -n "$NAMESPACE" --no-headers | awk '{print " " $1}'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "========================================="
|
||||
echo "Debugging Pod: $POD_NAME"
|
||||
echo "Namespace: $NAMESPACE"
|
||||
echo "========================================="
|
||||
echo ""
|
||||
|
||||
# Pod details
|
||||
echo "Pod Details:"
|
||||
echo "------------"
|
||||
kubectl get pod "$POD_NAME" -n "$NAMESPACE" -o wide
|
||||
|
||||
# Pod describe
|
||||
echo ""
|
||||
echo "Pod Description:"
|
||||
echo "----------------"
|
||||
kubectl describe pod "$POD_NAME" -n "$NAMESPACE"
|
||||
|
||||
# Container logs
|
||||
echo ""
|
||||
echo "Container Logs (last 50 lines):"
|
||||
echo "--------------------------------"
|
||||
CONTAINERS=$(kubectl get pod "$POD_NAME" -n "$NAMESPACE" -o jsonpath='{.spec.containers[*].name}')
|
||||
for CONTAINER in $CONTAINERS; do
|
||||
echo ""
|
||||
echo "=== Container: $CONTAINER ==="
|
||||
kubectl logs "$POD_NAME" -n "$NAMESPACE" -c "$CONTAINER" --tail=50 2>/dev/null || echo "No logs available"
|
||||
done
|
||||
|
||||
# Previous container logs (if crashed)
|
||||
echo ""
|
||||
echo "Previous Container Logs (if any):"
|
||||
echo "----------------------------------"
|
||||
for CONTAINER in $CONTAINERS; do
|
||||
echo ""
|
||||
echo "=== Container: $CONTAINER (previous) ==="
|
||||
kubectl logs "$POD_NAME" -n "$NAMESPACE" -c "$CONTAINER" --previous --tail=20 2>/dev/null || echo "No previous logs"
|
||||
done
|
||||
|
||||
# Resource usage
|
||||
echo ""
|
||||
echo "Resource Usage:"
|
||||
echo "---------------"
|
||||
kubectl top pod "$POD_NAME" -n "$NAMESPACE" 2>/dev/null || echo "Metrics not available"
|
||||
|
||||
# Events for this pod
|
||||
echo ""
|
||||
echo "Related Events:"
|
||||
echo "---------------"
|
||||
kubectl get events -n "$NAMESPACE" --field-selector involvedObject.name="$POD_NAME" --sort-by='.lastTimestamp'
|
||||
|
||||
echo ""
|
||||
echo "========================================="
|
||||
echo "Debug information complete"
|
||||
echo "========================================="
|
||||
@@ -0,0 +1,454 @@
|
||||
---
|
||||
name: kustomize
|
||||
description: Customize Kubernetes manifests without templating using Kustomize. Create base configurations with environment overlays, manage configuration variants, and patch resources declaratively. Use when managing Kubernetes configurations across multiple environments without Helm.
|
||||
license: MIT
|
||||
metadata:
|
||||
author: devops-skills
|
||||
version: "1.0"
|
||||
---
|
||||
|
||||
# Kustomize
|
||||
|
||||
Customize Kubernetes resources declaratively without templating.
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
Use this skill when:
|
||||
- Managing Kubernetes configs across environments
|
||||
- Patching existing manifests without modification
|
||||
- Creating configuration variants from bases
|
||||
- Customizing third-party manifests
|
||||
- Preferring declarative over templating approach
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- kubectl 1.14+ (includes kustomize)
|
||||
- Or standalone kustomize CLI
|
||||
- Basic Kubernetes manifest knowledge
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
myapp/
|
||||
├── base/
|
||||
│ ├── kustomization.yaml
|
||||
│ ├── deployment.yaml
|
||||
│ ├── service.yaml
|
||||
│ └── configmap.yaml
|
||||
└── overlays/
|
||||
├── development/
|
||||
│ ├── kustomization.yaml
|
||||
│ └── replica-patch.yaml
|
||||
├── staging/
|
||||
│ ├── kustomization.yaml
|
||||
│ └── namespace.yaml
|
||||
└── production/
|
||||
├── kustomization.yaml
|
||||
├── replica-patch.yaml
|
||||
└── resource-patch.yaml
|
||||
```
|
||||
|
||||
## Base Configuration
|
||||
|
||||
### kustomization.yaml
|
||||
|
||||
```yaml
|
||||
# base/kustomization.yaml
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
resources:
|
||||
- deployment.yaml
|
||||
- service.yaml
|
||||
- configmap.yaml
|
||||
|
||||
commonLabels:
|
||||
app: myapp
|
||||
|
||||
commonAnnotations:
|
||||
managed-by: kustomize
|
||||
```
|
||||
|
||||
### Base Resources
|
||||
|
||||
```yaml
|
||||
# base/deployment.yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: myapp
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: myapp
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: myapp
|
||||
spec:
|
||||
containers:
|
||||
- name: myapp
|
||||
image: myapp:latest
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
resources:
|
||||
requests:
|
||||
memory: "64Mi"
|
||||
cpu: "100m"
|
||||
limits:
|
||||
memory: "128Mi"
|
||||
cpu: "200m"
|
||||
```
|
||||
|
||||
## Overlays
|
||||
|
||||
### Development Overlay
|
||||
|
||||
```yaml
|
||||
# overlays/development/kustomization.yaml
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
resources:
|
||||
- ../../base
|
||||
|
||||
namespace: myapp-dev
|
||||
|
||||
namePrefix: dev-
|
||||
|
||||
commonLabels:
|
||||
environment: development
|
||||
|
||||
images:
|
||||
- name: myapp
|
||||
newTag: dev-latest
|
||||
```
|
||||
|
||||
### Production Overlay
|
||||
|
||||
```yaml
|
||||
# overlays/production/kustomization.yaml
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
resources:
|
||||
- ../../base
|
||||
|
||||
namespace: myapp-prod
|
||||
|
||||
namePrefix: prod-
|
||||
|
||||
commonLabels:
|
||||
environment: production
|
||||
|
||||
replicas:
|
||||
- name: myapp
|
||||
count: 5
|
||||
|
||||
images:
|
||||
- name: myapp
|
||||
newName: registry.example.com/myapp
|
||||
newTag: v2.0.0
|
||||
|
||||
patches:
|
||||
- path: resource-patch.yaml
|
||||
```
|
||||
|
||||
## Patching
|
||||
|
||||
### Strategic Merge Patch
|
||||
|
||||
```yaml
|
||||
# overlays/production/resource-patch.yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: myapp
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: myapp
|
||||
resources:
|
||||
requests:
|
||||
memory: "256Mi"
|
||||
cpu: "500m"
|
||||
limits:
|
||||
memory: "512Mi"
|
||||
cpu: "1000m"
|
||||
```
|
||||
|
||||
### JSON Patch
|
||||
|
||||
```yaml
|
||||
# kustomization.yaml
|
||||
patches:
|
||||
- target:
|
||||
kind: Deployment
|
||||
name: myapp
|
||||
patch: |-
|
||||
- op: replace
|
||||
path: /spec/replicas
|
||||
value: 5
|
||||
- op: add
|
||||
path: /spec/template/spec/containers/0/env
|
||||
value:
|
||||
- name: LOG_LEVEL
|
||||
value: info
|
||||
```
|
||||
|
||||
### Inline Patches
|
||||
|
||||
```yaml
|
||||
# kustomization.yaml
|
||||
patches:
|
||||
- patch: |-
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: myapp
|
||||
spec:
|
||||
replicas: 3
|
||||
target:
|
||||
kind: Deployment
|
||||
name: myapp
|
||||
```
|
||||
|
||||
## Configuration Generation
|
||||
|
||||
### ConfigMap Generator
|
||||
|
||||
```yaml
|
||||
# kustomization.yaml
|
||||
configMapGenerator:
|
||||
- name: myapp-config
|
||||
literals:
|
||||
- APP_ENV=production
|
||||
- LOG_LEVEL=info
|
||||
files:
|
||||
- config.yaml
|
||||
envs:
|
||||
- config.env
|
||||
options:
|
||||
disableNameSuffixHash: false
|
||||
```
|
||||
|
||||
### Secret Generator
|
||||
|
||||
```yaml
|
||||
# kustomization.yaml
|
||||
secretGenerator:
|
||||
- name: myapp-secrets
|
||||
literals:
|
||||
- api-key=secret123
|
||||
files:
|
||||
- tls.crt
|
||||
- tls.key
|
||||
type: kubernetes.io/tls
|
||||
```
|
||||
|
||||
## Image Transformations
|
||||
|
||||
```yaml
|
||||
# kustomization.yaml
|
||||
images:
|
||||
# Change tag
|
||||
- name: myapp
|
||||
newTag: v2.0.0
|
||||
|
||||
# Change registry
|
||||
- name: myapp
|
||||
newName: registry.example.com/myapp
|
||||
newTag: v2.0.0
|
||||
|
||||
# Use digest
|
||||
- name: myapp
|
||||
digest: sha256:abc123...
|
||||
```
|
||||
|
||||
## Resource Transformations
|
||||
|
||||
### Name Prefix/Suffix
|
||||
|
||||
```yaml
|
||||
# kustomization.yaml
|
||||
namePrefix: prod-
|
||||
nameSuffix: -v2
|
||||
```
|
||||
|
||||
### Namespace
|
||||
|
||||
```yaml
|
||||
# kustomization.yaml
|
||||
namespace: production
|
||||
```
|
||||
|
||||
### Labels and Annotations
|
||||
|
||||
```yaml
|
||||
# kustomization.yaml
|
||||
commonLabels:
|
||||
app.kubernetes.io/name: myapp
|
||||
app.kubernetes.io/environment: production
|
||||
|
||||
commonAnnotations:
|
||||
example.com/owner: team-a
|
||||
```
|
||||
|
||||
### Replicas
|
||||
|
||||
```yaml
|
||||
# kustomization.yaml
|
||||
replicas:
|
||||
- name: myapp
|
||||
count: 5
|
||||
- name: worker
|
||||
count: 3
|
||||
```
|
||||
|
||||
## Components
|
||||
|
||||
```yaml
|
||||
# components/monitoring/kustomization.yaml
|
||||
apiVersion: kustomize.config.k8s.io/v1alpha1
|
||||
kind: Component
|
||||
|
||||
resources:
|
||||
- servicemonitor.yaml
|
||||
|
||||
patches:
|
||||
- patch: |-
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: myapp
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
prometheus.io/scrape: "true"
|
||||
prometheus.io/port: "8080"
|
||||
```
|
||||
|
||||
```yaml
|
||||
# overlays/production/kustomization.yaml
|
||||
components:
|
||||
- ../../components/monitoring
|
||||
```
|
||||
|
||||
## Remote Resources
|
||||
|
||||
```yaml
|
||||
# kustomization.yaml
|
||||
resources:
|
||||
# Remote Git repository
|
||||
- https://github.com/org/manifests//base?ref=v1.0.0
|
||||
|
||||
# Remote URL
|
||||
- https://raw.githubusercontent.com/org/repo/main/deployment.yaml
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
# Build and view output
|
||||
kubectl kustomize overlays/production
|
||||
|
||||
# Apply to cluster
|
||||
kubectl apply -k overlays/production
|
||||
|
||||
# Delete resources
|
||||
kubectl delete -k overlays/production
|
||||
|
||||
# View diff
|
||||
kubectl diff -k overlays/production
|
||||
|
||||
# Build with standalone kustomize
|
||||
kustomize build overlays/production
|
||||
|
||||
# Build and apply
|
||||
kustomize build overlays/production | kubectl apply -f -
|
||||
```
|
||||
|
||||
## Helm Chart Integration
|
||||
|
||||
```yaml
|
||||
# kustomization.yaml
|
||||
helmCharts:
|
||||
- name: prometheus
|
||||
repo: https://prometheus-community.github.io/helm-charts
|
||||
version: 25.0.0
|
||||
releaseName: prometheus
|
||||
namespace: monitoring
|
||||
valuesFile: values.yaml
|
||||
includeCRDs: true
|
||||
```
|
||||
|
||||
## Variable Substitution
|
||||
|
||||
```yaml
|
||||
# kustomization.yaml
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
resources:
|
||||
- deployment.yaml
|
||||
|
||||
replacements:
|
||||
- source:
|
||||
kind: ConfigMap
|
||||
name: myapp-config
|
||||
fieldPath: data.APP_VERSION
|
||||
targets:
|
||||
- select:
|
||||
kind: Deployment
|
||||
name: myapp
|
||||
fieldPaths:
|
||||
- spec.template.spec.containers.[name=myapp].image
|
||||
options:
|
||||
delimiter: ':'
|
||||
index: 1
|
||||
```
|
||||
|
||||
## Common Issues
|
||||
|
||||
### Issue: Name Hash Conflicts
|
||||
**Problem**: Resources not updating when ConfigMap changes
|
||||
**Solution**: Enable name suffix hash (default) or use replacement
|
||||
|
||||
### Issue: Patch Not Applying
|
||||
**Problem**: Strategic merge patch doesn't work
|
||||
**Solution**: Verify resource names match, use JSON patch for complex changes
|
||||
|
||||
### Issue: Remote Resource Fails
|
||||
**Problem**: Cannot fetch remote resources
|
||||
**Solution**: Check URL, verify ref/tag exists, ensure network access
|
||||
|
||||
### Issue: Label Selector Mismatch
|
||||
**Problem**: commonLabels breaks selectors
|
||||
**Solution**: Use includeSelectors: false or exclude specific resources
|
||||
|
||||
```yaml
|
||||
commonLabels:
|
||||
app: myapp
|
||||
configurations:
|
||||
- labelExclusions.yaml
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Keep base manifests environment-agnostic
|
||||
- Use overlays for environment-specific config
|
||||
- Prefer strategic merge patches for simple changes
|
||||
- Use components for optional features
|
||||
- Pin remote resource versions
|
||||
- Enable ConfigMap/Secret hash suffixes
|
||||
- Document overlay structure in README
|
||||
- Test builds before applying
|
||||
|
||||
## Related Skills
|
||||
|
||||
- [kubernetes-ops](../kubernetes-ops/) - K8s fundamentals
|
||||
- [helm-charts](../helm-charts/) - Helm alternative
|
||||
- [argocd-gitops](../argocd-gitops/) - GitOps deployment
|
||||
@@ -0,0 +1,461 @@
|
||||
---
|
||||
name: openshift
|
||||
description: Manage Red Hat OpenShift clusters and deployments. Configure projects, routes, builds, and deploy applications using OpenShift-specific features. Use when working with OpenShift Container Platform or OKD for enterprise Kubernetes.
|
||||
license: MIT
|
||||
metadata:
|
||||
author: devops-skills
|
||||
version: "1.0"
|
||||
---
|
||||
|
||||
# OpenShift
|
||||
|
||||
Deploy and manage applications on Red Hat OpenShift Container Platform.
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
Use this skill when:
|
||||
- Deploying applications to OpenShift clusters
|
||||
- Using OpenShift-specific features (Routes, BuildConfigs)
|
||||
- Managing projects and RBAC in OpenShift
|
||||
- Implementing S2I (Source-to-Image) builds
|
||||
- Working with OpenShift Operators
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- OpenShift cluster access
|
||||
- oc CLI installed
|
||||
- Basic Kubernetes knowledge
|
||||
|
||||
## CLI Basics
|
||||
|
||||
### Authentication
|
||||
|
||||
```bash
|
||||
# Login to cluster
|
||||
oc login https://api.cluster.example.com:6443 -u admin -p password
|
||||
|
||||
# Login with token
|
||||
oc login --token=sha256~xxxx --server=https://api.cluster.example.com:6443
|
||||
|
||||
# Check current context
|
||||
oc whoami
|
||||
oc whoami --show-server
|
||||
oc whoami --show-context
|
||||
|
||||
# Logout
|
||||
oc logout
|
||||
```
|
||||
|
||||
### Project Management
|
||||
|
||||
```bash
|
||||
# Create project (namespace)
|
||||
oc new-project myapp --display-name="My App" --description="My Application"
|
||||
|
||||
# Switch project
|
||||
oc project myapp
|
||||
|
||||
# List projects
|
||||
oc projects
|
||||
|
||||
# Delete project
|
||||
oc delete project myapp
|
||||
```
|
||||
|
||||
## Deploying Applications
|
||||
|
||||
### From Image
|
||||
|
||||
```bash
|
||||
# Deploy from container image
|
||||
oc new-app --image=nginx:latest --name=webserver
|
||||
|
||||
# Deploy from Docker Hub
|
||||
oc new-app docker.io/library/nginx:latest
|
||||
|
||||
# Deploy with environment variables
|
||||
oc new-app myimage:latest \
|
||||
-e DATABASE_URL=postgres://localhost/db \
|
||||
-e APP_ENV=production
|
||||
```
|
||||
|
||||
### From Source (S2I)
|
||||
|
||||
```bash
|
||||
# Deploy from Git repository
|
||||
oc new-app https://github.com/org/myapp.git
|
||||
|
||||
# Specify builder image
|
||||
oc new-app nodejs:18~https://github.com/org/nodejs-app.git
|
||||
|
||||
# With context directory
|
||||
oc new-app https://github.com/org/monorepo.git \
|
||||
--context-dir=backend \
|
||||
--name=backend-api
|
||||
```
|
||||
|
||||
### From Template
|
||||
|
||||
```bash
|
||||
# List available templates
|
||||
oc get templates -n openshift
|
||||
|
||||
# Deploy from template
|
||||
oc new-app postgresql-persistent \
|
||||
-p POSTGRESQL_USER=user \
|
||||
-p POSTGRESQL_PASSWORD=secret \
|
||||
-p POSTGRESQL_DATABASE=mydb
|
||||
```
|
||||
|
||||
## Routes
|
||||
|
||||
### Creating Routes
|
||||
|
||||
```yaml
|
||||
apiVersion: route.openshift.io/v1
|
||||
kind: Route
|
||||
metadata:
|
||||
name: myapp
|
||||
spec:
|
||||
host: myapp.apps.cluster.example.com
|
||||
to:
|
||||
kind: Service
|
||||
name: myapp
|
||||
weight: 100
|
||||
port:
|
||||
targetPort: 8080
|
||||
tls:
|
||||
termination: edge
|
||||
insecureEdgeTerminationPolicy: Redirect
|
||||
```
|
||||
|
||||
```bash
|
||||
# Create route via CLI
|
||||
oc expose svc/myapp
|
||||
|
||||
# Create with custom hostname
|
||||
oc create route edge myapp \
|
||||
--service=myapp \
|
||||
--hostname=myapp.apps.cluster.example.com
|
||||
|
||||
# Create passthrough route (TLS termination at pod)
|
||||
oc create route passthrough myapp-secure --service=myapp
|
||||
```
|
||||
|
||||
### A/B Testing
|
||||
|
||||
```yaml
|
||||
apiVersion: route.openshift.io/v1
|
||||
kind: Route
|
||||
metadata:
|
||||
name: myapp
|
||||
spec:
|
||||
to:
|
||||
kind: Service
|
||||
name: myapp-v1
|
||||
weight: 90
|
||||
alternateBackends:
|
||||
- kind: Service
|
||||
name: myapp-v2
|
||||
weight: 10
|
||||
```
|
||||
|
||||
## Build Configurations
|
||||
|
||||
### BuildConfig
|
||||
|
||||
```yaml
|
||||
apiVersion: build.openshift.io/v1
|
||||
kind: BuildConfig
|
||||
metadata:
|
||||
name: myapp
|
||||
spec:
|
||||
source:
|
||||
type: Git
|
||||
git:
|
||||
uri: https://github.com/org/myapp.git
|
||||
ref: main
|
||||
strategy:
|
||||
type: Docker
|
||||
dockerStrategy:
|
||||
dockerfilePath: Dockerfile
|
||||
output:
|
||||
to:
|
||||
kind: ImageStreamTag
|
||||
name: myapp:latest
|
||||
triggers:
|
||||
- type: ConfigChange
|
||||
- type: GitHub
|
||||
github:
|
||||
secret: webhook-secret
|
||||
```
|
||||
|
||||
### S2I Build
|
||||
|
||||
```yaml
|
||||
apiVersion: build.openshift.io/v1
|
||||
kind: BuildConfig
|
||||
metadata:
|
||||
name: myapp
|
||||
spec:
|
||||
source:
|
||||
type: Git
|
||||
git:
|
||||
uri: https://github.com/org/myapp.git
|
||||
strategy:
|
||||
type: Source
|
||||
sourceStrategy:
|
||||
from:
|
||||
kind: ImageStreamTag
|
||||
namespace: openshift
|
||||
name: nodejs:18-ubi8
|
||||
env:
|
||||
- name: NPM_RUN
|
||||
value: start
|
||||
output:
|
||||
to:
|
||||
kind: ImageStreamTag
|
||||
name: myapp:latest
|
||||
```
|
||||
|
||||
### Build Commands
|
||||
|
||||
```bash
|
||||
# Start build
|
||||
oc start-build myapp
|
||||
|
||||
# Start build from local source
|
||||
oc start-build myapp --from-dir=.
|
||||
|
||||
# Follow build logs
|
||||
oc start-build myapp --follow
|
||||
|
||||
# View build logs
|
||||
oc logs -f bc/myapp
|
||||
|
||||
# Cancel build
|
||||
oc cancel-build myapp-1
|
||||
```
|
||||
|
||||
## Image Streams
|
||||
|
||||
```yaml
|
||||
apiVersion: image.openshift.io/v1
|
||||
kind: ImageStream
|
||||
metadata:
|
||||
name: myapp
|
||||
spec:
|
||||
lookupPolicy:
|
||||
local: true
|
||||
tags:
|
||||
- name: latest
|
||||
from:
|
||||
kind: DockerImage
|
||||
name: registry.example.com/myapp:latest
|
||||
importPolicy:
|
||||
scheduled: true
|
||||
```
|
||||
|
||||
```bash
|
||||
# Create image stream
|
||||
oc create imagestream myapp
|
||||
|
||||
# Import image
|
||||
oc import-image myapp:latest \
|
||||
--from=docker.io/library/nginx:latest \
|
||||
--confirm
|
||||
|
||||
# Tag image
|
||||
oc tag myapp:latest myapp:production
|
||||
```
|
||||
|
||||
## Deployment Configs
|
||||
|
||||
```yaml
|
||||
apiVersion: apps.openshift.io/v1
|
||||
kind: DeploymentConfig
|
||||
metadata:
|
||||
name: myapp
|
||||
spec:
|
||||
replicas: 3
|
||||
selector:
|
||||
app: myapp
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: myapp
|
||||
spec:
|
||||
containers:
|
||||
- name: myapp
|
||||
image: myapp:latest
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
resources:
|
||||
requests:
|
||||
memory: "128Mi"
|
||||
cpu: "100m"
|
||||
limits:
|
||||
memory: "256Mi"
|
||||
cpu: "500m"
|
||||
triggers:
|
||||
- type: ConfigChange
|
||||
- type: ImageChange
|
||||
imageChangeParams:
|
||||
automatic: true
|
||||
containerNames:
|
||||
- myapp
|
||||
from:
|
||||
kind: ImageStreamTag
|
||||
name: myapp:latest
|
||||
strategy:
|
||||
type: Rolling
|
||||
rollingParams:
|
||||
maxSurge: 25%
|
||||
maxUnavailable: 25%
|
||||
```
|
||||
|
||||
## ConfigMaps and Secrets
|
||||
|
||||
```bash
|
||||
# Create ConfigMap
|
||||
oc create configmap myapp-config \
|
||||
--from-literal=APP_ENV=production \
|
||||
--from-file=config.yaml
|
||||
|
||||
# Create Secret
|
||||
oc create secret generic myapp-secrets \
|
||||
--from-literal=password=secret123
|
||||
|
||||
# Mount as volume
|
||||
oc set volume dc/myapp \
|
||||
--add --name=config \
|
||||
--type=configmap \
|
||||
--configmap-name=myapp-config \
|
||||
--mount-path=/etc/config
|
||||
|
||||
# Set as environment
|
||||
oc set env dc/myapp --from=secret/myapp-secrets
|
||||
```
|
||||
|
||||
## Security Context Constraints
|
||||
|
||||
```bash
|
||||
# List SCCs
|
||||
oc get scc
|
||||
|
||||
# View SCC details
|
||||
oc describe scc restricted
|
||||
|
||||
# Grant SCC to service account
|
||||
oc adm policy add-scc-to-user anyuid -z myapp-sa -n myproject
|
||||
|
||||
# Create service account
|
||||
oc create serviceaccount myapp-sa
|
||||
```
|
||||
|
||||
### Custom SCC
|
||||
|
||||
```yaml
|
||||
apiVersion: security.openshift.io/v1
|
||||
kind: SecurityContextConstraints
|
||||
metadata:
|
||||
name: myapp-scc
|
||||
allowPrivilegedContainer: false
|
||||
runAsUser:
|
||||
type: MustRunAsNonRoot
|
||||
seLinuxContext:
|
||||
type: MustRunAs
|
||||
fsGroup:
|
||||
type: RunAsAny
|
||||
volumes:
|
||||
- configMap
|
||||
- secret
|
||||
- persistentVolumeClaim
|
||||
users:
|
||||
- system:serviceaccount:myproject:myapp-sa
|
||||
```
|
||||
|
||||
## Operators
|
||||
|
||||
```bash
|
||||
# List available operators
|
||||
oc get packagemanifests -n openshift-marketplace
|
||||
|
||||
# Subscribe to operator
|
||||
cat <<EOF | oc apply -f -
|
||||
apiVersion: operators.coreos.com/v1alpha1
|
||||
kind: Subscription
|
||||
metadata:
|
||||
name: prometheus
|
||||
namespace: openshift-operators
|
||||
spec:
|
||||
channel: stable
|
||||
name: prometheus
|
||||
source: community-operators
|
||||
sourceNamespace: openshift-marketplace
|
||||
EOF
|
||||
|
||||
# View installed operators
|
||||
oc get csv -n openshift-operators
|
||||
```
|
||||
|
||||
## Monitoring
|
||||
|
||||
```bash
|
||||
# View pod logs
|
||||
oc logs -f pod/myapp-1-xyz
|
||||
|
||||
# View events
|
||||
oc get events --sort-by='.lastTimestamp'
|
||||
|
||||
# Resource usage
|
||||
oc adm top pods
|
||||
oc adm top nodes
|
||||
|
||||
# Debug pod
|
||||
oc debug pod/myapp-1-xyz
|
||||
```
|
||||
|
||||
## Common Issues
|
||||
|
||||
### Issue: Build Fails
|
||||
**Problem**: S2I build cannot find dependencies
|
||||
**Solution**: Check builder image, verify source repository access
|
||||
|
||||
### Issue: Pod Security Violation
|
||||
**Problem**: Pod fails to start due to SCC
|
||||
**Solution**: Use appropriate SCC or modify container security context
|
||||
|
||||
### Issue: Route Not Working
|
||||
**Problem**: Cannot access application via route
|
||||
**Solution**: Verify service selector, check router pods, validate DNS
|
||||
|
||||
### Issue: Image Pull Error
|
||||
**Problem**: Cannot pull image from registry
|
||||
**Solution**: Create image pull secret, link to service account
|
||||
|
||||
```bash
|
||||
oc create secret docker-registry regcred \
|
||||
--docker-server=registry.example.com \
|
||||
--docker-username=user \
|
||||
--docker-password=pass
|
||||
|
||||
oc secrets link default regcred --for=pull
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Use Projects for isolation (not just namespaces)
|
||||
- Leverage ImageStreams for image management
|
||||
- Use BuildConfigs for CI/CD integration
|
||||
- Implement proper SCCs (avoid privileged)
|
||||
- Use Routes instead of Ingress
|
||||
- Leverage OpenShift templates for repeatability
|
||||
- Monitor with built-in Prometheus
|
||||
- Use Operators for complex applications
|
||||
|
||||
## Related Skills
|
||||
|
||||
- [kubernetes-ops](../kubernetes-ops/) - K8s fundamentals
|
||||
- [helm-charts](../helm-charts/) - Helm deployments
|
||||
- [container-registries](../../containers/container-registries/) - Image management
|
||||
Reference in New Issue
Block a user