devops-infra-github
1
总安装量
1
周安装量
#49613
全站排名
安装命令
npx skills add https://github.com/lcaparros/cicd-github-bun --skill devops-infra-github
Agent 安装分布
opencode
1
Skill 文档
DevOps & Infrastructure Skill
Overview
Expert guidance for containerization, orchestration, and CI/CD pipelines for Bun monorepo projects.
When to Use This Skill
- Creating Docker images for services
- Setting up Docker Compose for local development
- Configuring GitHub Actions for CI/CD
- Managing environment variables and secrets
- Automating deployments
Stack Context
- Runtime: Bun
- Containerization: Docker (multi-stage builds with
oven/bun:alpine) - Orchestration: Docker Compose
- CI/CD: GitHub Actions
- Version Management: Changesets
- Registry: Docker Hub / GitHub Container Registry
Project Structure
.
âââ .github/
â âââ workflows/
â âââ service-a-ci.yml
â âââ service-b-ci.yml
âââ packages/
â âââ service-a/
â â âââ Dockerfile
â â âââ .dockerignore
â â âââ docker-compose.yml
â âââ service-b/
â âââ Dockerfile
â âââ .dockerignore
â âââ docker-compose.yml
âââ .changeset/
âââ package.json
Workflows
1. Dockerfile for Bun Service
packages/my-service/Dockerfile:
# Multi-stage build for optimized image size
FROM oven/bun:alpine AS base
WORKDIR /app
# Install dependencies stage
FROM base AS deps
COPY package.json bun.lockb ./
RUN bun install --frozen-lockfile --production
# Build stage (if needed)
FROM base AS builder
COPY package.json bun.lockb ./
COPY src ./src
RUN bun install --frozen-lockfile
# Production stage
FROM base AS runner
WORKDIR /app
# Copy dependencies from deps stage
COPY /app/node_modules ./node_modules
COPY package.json ./
COPY src ./src
# Create non-root user
RUN addgroup -g 1001 -S bunuser && \
adduser -S bunuser -u 1001
USER bunuser
# Expose port
EXPOSE 3000
# Health check
HEALTHCHECK \
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1
# Start application
CMD ["bun", "src/index.js"]
.dockerignore:
node_modules
.env
.env.*
*.log
.git
.gitignore
README.md
CHANGELOG.md
.changeset
dist
coverage
.vscode
.idea
2. Docker Compose for Local Development
packages/my-service/docker-compose.yml:
version: '3.9'
services:
# Main service
api:
build:
context: .
dockerfile: Dockerfile
container_name: my-service-api
ports:
- "3000:3000"
environment:
- NODE_ENV=development
- PORT=3000
- MONGO_URI=mongodb://mongo:27017
- DB_NAME=mydb
- REDIS_URI=redis://redis:6379
depends_on:
mongo:
condition: service_healthy
redis:
condition: service_healthy
networks:
- app-network
restart: unless-stopped
volumes:
# Hot reload for development
- ./src:/app/src:ro
- ./package.json:/app/package.json:ro
# MongoDB
mongo:
image: mongo:7-jammy
container_name: my-service-mongo
ports:
- "27017:27017"
environment:
- MONGO_INITDB_DATABASE=mydb
volumes:
- mongo-data:/data/db
- ./mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:ro
networks:
- app-network
restart: unless-stopped
healthcheck:
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s
# Redis
redis:
image: redis:7-alpine
container_name: my-service-redis
ports:
- "6379:6379"
command: redis-server --appendonly yes
volumes:
- redis-data:/data
networks:
- app-network
restart: unless-stopped
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 5
start_period: 5s
volumes:
mongo-data:
driver: local
redis-data:
driver: local
networks:
app-network:
driver: bridge
Usage:
# Start all services
docker compose up -d
# View logs
docker compose logs -f
# Stop services
docker compose down
# Rebuild and start
docker compose up --build -d
# Remove volumes (clean state)
docker compose down -v
3. MongoDB Initialization Script
packages/my-service/mongo-init.js:
// Run on first container start
db = db.getSiblingDB('mydb')
// Create collections
db.createCollection('users')
db.createCollection('posts')
// Create indexes
db.users.createIndex({ email: 1 }, { unique: true })
db.posts.createIndex({ createdAt: -1 })
// Insert seed data
db.users.insertMany([
{
name: 'Admin User',
email: 'admin@example.com',
createdAt: new Date()
}
])
print('MongoDB initialized successfully')
4. GitHub Actions CI/CD Pipeline
.github/workflows/service-a-ci.yml:
name: Service A CI/CD
on:
push:
branches: [main, develop]
paths:
- 'packages/service-a/**'
- '.changeset/**'
pull_request:
branches: [main]
paths:
- 'packages/service-a/**'
env:
SERVICE_NAME: service-a
SERVICE_PATH: packages/service-a
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}/service-a
jobs:
# Lint and test
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v1
with:
bun-version: latest
- name: Install dependencies
run: bun install --frozen-lockfile
working-directory: ${{ env.SERVICE_PATH }}
- name: Lint
run: bun run lint
working-directory: ${{ env.SERVICE_PATH }}
- name: Test
run: bun test
working-directory: ${{ env.SERVICE_PATH }}
# Check for version changes
version-check:
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
outputs:
has-changeset: ${{ steps.changeset.outputs.hasChangesets }}
version: ${{ steps.get-version.outputs.version }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Bun
uses: oven-sh/setup-bun@v1
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Check for changesets
id: changeset
uses: changesets/action@v1
with:
version: bun run version
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Get package version
id: get-version
run: |
VERSION=$(node -p "require('./package.json').version")
echo "version=$VERSION" >> $GITHUB_OUTPUT
working-directory: ${{ env.SERVICE_PATH }}
# Build and push Docker image
build-and-push:
needs: [test, version-check]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=semver,pattern={{version}},value=${{ needs.version-check.outputs.version }}
type=semver,pattern={{major}}.{{minor}},value=${{ needs.version-check.outputs.version }}
type=raw,value=latest,enable={{is_default_branch}}
type=sha,prefix={{branch}}-
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: ${{ env.SERVICE_PATH }}
file: ${{ env.SERVICE_PATH }}/Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
# Create GitHub Release
release:
needs: [version-check, build-and-push]
if: needs.version-check.outputs.has-changeset == 'true'
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- name: Create Release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ env.SERVICE_NAME }}@v${{ needs.version-check.outputs.version }}
release_name: ${{ env.SERVICE_NAME }} v${{ needs.version-check.outputs.version }}
body_path: ${{ env.SERVICE_PATH }}/CHANGELOG.md
draft: false
prerelease: false
# Deploy (placeholder)
deploy:
needs: [build-and-push]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- name: Deploy to Production
run: |
echo "Deployment step - integrate with your deployment platform"
echo "Image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.version-check.outputs.version }}"
# Add deployment commands here (e.g., kubectl, SSH, etc.)
5. Multi-Service CI/CD with Matrix
.github/workflows/monorepo-ci.yml:
name: Monorepo CI/CD
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
# Detect changed services
detect-changes:
runs-on: ubuntu-latest
outputs:
services: ${{ steps.filter.outputs.changes }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v2
id: filter
with:
filters: |
service-a:
- 'packages/service-a/**'
service-b:
- 'packages/service-b/**'
web:
- 'packages/web/**'
# Test changed services
test:
needs: detect-changes
if: ${{ needs.detect-changes.outputs.services != '[]' }}
runs-on: ubuntu-latest
strategy:
matrix:
service: ${{ fromJSON(needs.detect-changes.outputs.services) }}
steps:
- uses: actions/checkout@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v1
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Test ${{ matrix.service }}
run: |
cd packages/${{ matrix.service }}
bun run lint
bun test
6. Environment Variables Management
Development (.env):
# Service
PORT=3000
NODE_ENV=development
# MongoDB
MONGO_URI=mongodb://localhost:27017
DB_NAME=mydb_dev
# Redis
REDIS_URI=redis://localhost:6379
# Auth
API_TOKEN=dev-token-12345
Production (GitHub Secrets):
MONGO_URI: Production MongoDB connection stringREDIS_URI: Production Redis connection stringAPI_TOKEN: Production API tokenDOCKER_USERNAME: Docker registry usernameDOCKER_PASSWORD: Docker registry password
Using secrets in GitHub Actions:
- name: Deploy
env:
MONGO_URI: ${{ secrets.MONGO_URI }}
REDIS_URI: ${{ secrets.REDIS_URI }}
API_TOKEN: ${{ secrets.API_TOKEN }}
7. Docker Build Optimization
Multi-architecture builds:
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push
uses: docker/build-push-action@v5
with:
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
cache-from: type=gha
cache-to: type=gha,mode=max
8. Docker Compose for Production
docker-compose.prod.yml:
version: '3.9'
services:
api:
image: ghcr.io/org/service-a:latest
container_name: service-a-api
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- PORT=3000
env_file:
- .env.production
depends_on:
- mongo
- redis
networks:
- app-network
restart: always
deploy:
resources:
limits:
cpus: '1'
memory: 512M
reservations:
cpus: '0.5'
memory: 256M
mongo:
image: mongo:7-jammy
container_name: service-a-mongo
environment:
- MONGO_INITDB_ROOT_USERNAME=${MONGO_USER}
- MONGO_INITDB_ROOT_PASSWORD=${MONGO_PASSWORD}
volumes:
- mongo-data:/data/db
networks:
- app-network
restart: always
redis:
image: redis:7-alpine
container_name: service-a-redis
command: redis-server --requirepass ${REDIS_PASSWORD}
volumes:
- redis-data:/data
networks:
- app-network
restart: always
volumes:
mongo-data:
redis-data:
networks:
app-network:
driver: bridge
9. Deployment Script
deploy.sh:
#!/bin/bash
set -e
SERVICE_NAME=$1
VERSION=$2
if [ -z "$SERVICE_NAME" ] || [ -z "$VERSION" ]; then
echo "Usage: ./deploy.sh <service-name> <version>"
exit 1
fi
echo "Deploying $SERVICE_NAME version $VERSION..."
# Pull latest image
docker pull ghcr.io/org/$SERVICE_NAME:$VERSION
# Stop current container
docker compose -f packages/$SERVICE_NAME/docker-compose.prod.yml down
# Start new version
docker compose -f packages/$SERVICE_NAME/docker-compose.prod.yml up -d
# Check health
sleep 5
if curl -f http://localhost:3000/health; then
echo "â
Deployment successful"
else
echo "â Health check failed"
exit 1
fi
10. Monitoring and Logging
Docker logging configuration:
services:
api:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
View logs:
# Follow logs for all services
docker compose logs -f
# Follow logs for specific service
docker compose logs -f api
# View last 100 lines
docker compose logs --tail=100 api
Best Practices
-
Docker:
- Use multi-stage builds to reduce image size
- Use
oven/bun:alpinefor smallest images - Run as non-root user
- Include health checks
- Use
.dockerignoreeffectively
-
Docker Compose:
- Use health checks for dependencies
- Define restart policies
- Use volumes for persistent data
- Network isolation with custom networks
- Set resource limits in production
-
CI/CD:
- Run tests before building
- Use path filters to only build changed services
- Tag images with semantic versions
- Cache dependencies for faster builds
- Use GitHub Secrets for sensitive data
-
Versioning:
- Use Changesets for version management
- Automate version bumps on merge to main
- Create GitHub Releases automatically
- Tag format:
service-name@vX.X.X
-
Secrets:
- Never commit
.envfiles - Use GitHub Secrets for CI/CD
- Use environment-specific
.envfiles - Rotate secrets regularly
- Never commit
-
Deployment:
- Use health checks before routing traffic
- Implement zero-downtime deployments
- Keep rollback capability
- Monitor logs and metrics
Common Commands
Docker:
# Build image
docker build -t my-service:latest .
# Run container
docker run -p 3000:3000 my-service:latest
# View running containers
docker ps
# Stop container
docker stop <container-id>
# Remove container
docker rm <container-id>
# View logs
docker logs -f <container-id>
Docker Compose:
# Start services
docker compose up -d
# Stop services
docker compose down
# Rebuild services
docker compose build
# View logs
docker compose logs -f
# Execute command in container
docker compose exec api bun run migrate