sync
This commit is contained in:
277
CD-README.md
Normal file
277
CD-README.md
Normal file
@@ -0,0 +1,277 @@
|
||||
# Reusable CD Workflow for Kubernetes Services
|
||||
|
||||
This directory contains a reusable CD (Continuous Deployment) workflow that automatically detects and deploys your Kubernetes services, whether they use Helm + Kubernetes or just Kubernetes manifests, with flexible secret management.
|
||||
|
||||
## Features
|
||||
|
||||
- **Automatic Detection**: Automatically detects if your service uses Helm (helmfile.yaml) or just Kubernetes manifests
|
||||
- **Conditional Deployment**: Only runs Helm deployment when helmfile.yaml exists
|
||||
- **Flexible Paths**: Configurable paths for k8s directory and helmfile
|
||||
- **Smart Secret Management**: Flexible JSON-based secret creation system
|
||||
- **Branch Flexibility**: Deploy from any branch (defaults to main)
|
||||
- **Comprehensive Summary**: Provides a clear summary of what was deployed
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage (Recommended)
|
||||
|
||||
Simply call the workflow without any parameters - it will automatically detect your service type:
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
deploy:
|
||||
uses: ./.gitea/workflows/cd.yaml
|
||||
```
|
||||
|
||||
### With Custom Secrets
|
||||
|
||||
For services that need custom secrets (like your original example):
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
deploy:
|
||||
uses: ./.gitea/workflows/cd.yaml
|
||||
with:
|
||||
custom_secrets: |
|
||||
[
|
||||
{
|
||||
"name": "oidc",
|
||||
"type": "generic",
|
||||
"data": "{\"clientId\": \"${{ secrets.OIDC_CLIENT_ID }}\", \"clientSecret\": \"${{ secrets.OIDC_CLIENT_SECRET }}\"}"
|
||||
},
|
||||
{
|
||||
"name": "root-user",
|
||||
"type": "generic",
|
||||
"data": "{\"rootUser\": \"${{ secrets.MINIO_ROOT_USER }}\", \"rootPassword\": \"${{ secrets.MINIO_ROOT_PASSWORD }}\"}"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Advanced Usage with Custom Paths
|
||||
|
||||
If your service uses non-standard directory names:
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
deploy:
|
||||
uses: ./.gitea/workflows/cd.yaml
|
||||
with:
|
||||
k8s_dir: 'kubernetes/'
|
||||
helmfile_path: 'helm/helmfile.yaml'
|
||||
custom_secrets: |
|
||||
[
|
||||
{
|
||||
"name": "database-credentials",
|
||||
"type": "generic",
|
||||
"data": "{\"username\": \"${{ secrets.DB_USERNAME }}\", \"password\": \"${{ secrets.DB_PASSWORD }}\"}"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Deploy from Different Branch
|
||||
|
||||
Deploy from a staging or feature branch:
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
deploy-staging:
|
||||
uses: ./.gitea/workflows/cd.yaml
|
||||
with:
|
||||
deploy_branch: 'staging'
|
||||
custom_secrets: |
|
||||
[
|
||||
{
|
||||
"name": "staging-config",
|
||||
"type": "generic",
|
||||
"data": "{\"environment\": \"staging\", \"debug\": \"true\"}"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Force Skip Helm Deployment
|
||||
|
||||
If you want to skip Helm deployment even when helmfile.yaml exists:
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
deploy:
|
||||
uses: ./.gitea/workflows/cd.yaml
|
||||
with:
|
||||
skip_helm_deployment: true
|
||||
custom_secrets: |
|
||||
[
|
||||
{
|
||||
"name": "app-config",
|
||||
"type": "generic",
|
||||
"data": "{\"apiUrl\": \"${{ secrets.API_URL }}\", \"apiKey\": \"${{ secrets.API_KEY }}\"}"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## Input Parameters
|
||||
|
||||
| Parameter | Description | Default | Required |
|
||||
|-----------|-------------|---------|----------|
|
||||
| `k8s_dir` | Path to Kubernetes manifests directory | `k8s/` | No |
|
||||
| `helmfile_path` | Path to helmfile.yaml | `helmfile.yaml` | No |
|
||||
| `skip_helm_deployment` | Skip Helm deployment even if helmfile exists | `false` | No |
|
||||
| `custom_secrets` | JSON array of secrets to create | `[]` | No |
|
||||
| `deploy_branch` | Branch to deploy from | `main` | No |
|
||||
|
||||
## Custom Secrets Format
|
||||
|
||||
The `custom_secrets` parameter accepts a JSON array where each secret object has:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "secret-name",
|
||||
"type": "secret-type",
|
||||
"data": "{\"key1\": \"value1\", \"key2\": \"value2\"}"
|
||||
}
|
||||
```
|
||||
|
||||
### Secret Object Properties
|
||||
|
||||
- **`name`** (required): The name of the Kubernetes secret
|
||||
- **`type`** (optional): The type of Kubernetes secret (defaults to "generic")
|
||||
- **`data`** (required): JSON string containing the secret data
|
||||
|
||||
### Supported Secret Types
|
||||
|
||||
- `generic`: Generic secret (most common)
|
||||
- `docker-registry`: For Docker registry credentials
|
||||
- `tls`: For TLS certificates
|
||||
- `ssh-auth`: For SSH authentication
|
||||
- `basic-auth`: For basic authentication
|
||||
|
||||
### Example Secret Configurations
|
||||
|
||||
#### OIDC Configuration
|
||||
```json
|
||||
{
|
||||
"name": "oidc",
|
||||
"type": "generic",
|
||||
"data": "{\"clientId\": \"${{ secrets.OIDC_CLIENT_ID }}\", \"clientSecret\": \"${{ secrets.OIDC_CLIENT_SECRET }}\"}"
|
||||
}
|
||||
```
|
||||
|
||||
#### Database Credentials
|
||||
```json
|
||||
{
|
||||
"name": "database-credentials",
|
||||
"type": "generic",
|
||||
"data": "{\"username\": \"${{ secrets.DB_USERNAME }}\", \"password\": \"${{ secrets.DB_PASSWORD }}\"}"
|
||||
}
|
||||
```
|
||||
|
||||
#### Docker Registry
|
||||
```json
|
||||
{
|
||||
"name": "docker-registry",
|
||||
"type": "docker-registry",
|
||||
"data": "{\"username\": \"${{ secrets.DOCKER_USERNAME }}\", \"password\": \"${{ secrets.DOCKER_PASSWORD }}\"}"
|
||||
}
|
||||
```
|
||||
|
||||
## Directory Structure Requirements
|
||||
|
||||
### For Kubernetes-only services:
|
||||
```
|
||||
your-service/
|
||||
├── k8s/
|
||||
│ ├── deployment.yaml
|
||||
│ ├── service.yaml
|
||||
│ └── ...
|
||||
└── .gitea/workflows/your-workflow.yaml
|
||||
```
|
||||
|
||||
### For Helm + Kubernetes services:
|
||||
```
|
||||
your-service/
|
||||
├── k8s/
|
||||
│ ├── deployment.yaml
|
||||
│ ├── service.yaml
|
||||
│ └── ...
|
||||
├── helmfile.yaml
|
||||
└── .gitea/workflows/your-workflow.yaml
|
||||
```
|
||||
|
||||
## What Gets Deployed
|
||||
|
||||
### Always (if k8s/ directory exists):
|
||||
- Custom secrets creation (if specified)
|
||||
- Kubernetes manifest deployment using `kubectl apply`
|
||||
- Namespace extraction from repository name
|
||||
|
||||
### Conditionally (if helmfile.yaml exists and Helm deployment not skipped):
|
||||
- Custom secrets creation (if specified)
|
||||
- Helm chart deployment using `helmfile apply`
|
||||
- Kubernetes manifests in Helm context
|
||||
|
||||
## Migration from Your Original Workflow
|
||||
|
||||
Your original workflow had these hardcoded secrets:
|
||||
- `oidc` secret with OIDC_CLIENT_ID and OIDC_CLIENT_SECRET
|
||||
- `root-user` secret with MINIO_ROOT_USER and MINIO_ROOT_PASSWORD
|
||||
|
||||
To replicate this in the new workflow:
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
deploy:
|
||||
uses: ./.gitea/workflows/cd.yaml
|
||||
with:
|
||||
custom_secrets: |
|
||||
[
|
||||
{
|
||||
"name": "oidc",
|
||||
"type": "generic",
|
||||
"data": "{\"clientId\": \"${{ secrets.OIDC_CLIENT_ID }}\", \"clientSecret\": \"${{ secrets.OIDC_CLIENT_SECRET }}\"}"
|
||||
},
|
||||
{
|
||||
"name": "root-user",
|
||||
"type": "generic",
|
||||
"data": "{\"rootUser\": \"${{ secrets.MINIO_ROOT_USER }}\", \"rootPassword\": \"${{ secrets.MINIO_ROOT_PASSWORD }}\"}"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## Example Workflows
|
||||
|
||||
See `example-cd-usage.yaml` for complete examples of how to use this workflow in different scenarios.
|
||||
|
||||
## Dependencies
|
||||
|
||||
This workflow requires:
|
||||
- `./.gitea/actions/extract-namespace-from-repo-name` action
|
||||
- `KUBECONFIG` secret configured in your repository
|
||||
- Access to your Kubernetes cluster
|
||||
- `jq` for JSON parsing (included in ubuntu-latest runner)
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Helm deployment skipped unexpectedly
|
||||
- Check if `helmfile.yaml` exists in the expected location
|
||||
- Verify the `skip_helm_deployment` parameter is not set to `true`
|
||||
- Ensure the file path is correct if using custom paths
|
||||
|
||||
### Kubernetes deployment skipped
|
||||
- Verify the `k8s/` directory (or custom path) exists
|
||||
- Check the directory contains valid Kubernetes manifests
|
||||
|
||||
### Secret creation failures
|
||||
- Verify the JSON format is valid
|
||||
- Check that secret names are valid Kubernetes resource names
|
||||
- Ensure the `data` field contains valid JSON string
|
||||
|
||||
### Permission issues
|
||||
- Ensure the `KUBECONFIG` secret is properly configured
|
||||
- Verify the workflow has access to your Kubernetes cluster
|
||||
- Check that the namespace exists and is accessible
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- **Secret Data**: The `data` field in custom_secrets should contain the actual secret values, not references to GitHub secrets
|
||||
- **Repository Secrets**: Store sensitive values in GitHub repository secrets and reference them in the workflow
|
||||
- **Access Control**: Ensure only authorized users can trigger deployments
|
||||
- **Audit Trail**: All deployments are logged and visible in the GitHub Actions history
|
||||
Reference in New Issue
Block a user