正在学习

7.5 Deploying with Claude-Guided CI/CD

System setup

ENV PYTHONDONTWRITEBYTECODE=1 \

PYTHONUNBUFFERED=1

WORKDIR /app

Install runtime deps

COPY requirements.txt .

RUN pip install --no-cache-dir -r requirements.txt

Copy app

COPY app.py .

Expose port and launch

EXPOSE 8000

CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "2"]


docker-compose.yml (optional local “prod-like” run)

version: "3.9"

services:

taskflow:

build: .

image: taskflow:local

ports:

  • "8000:8000"

restart: unless-stopped


Run locally:

docker compose up --build

visit http://localhost:8000/health


deploy.sh

This script runs on your remote server (or via SSH) to pull and restart the service using a simple container. It is idempotent and safe to re-run.

#!/usr/bin/env bash

deploy.sh – pull and restart TaskFlow service

Usage (on remote host or via SSH): ./deploy.sh

Example: ./deploy.sh ghcr.io/your-org/taskflow:main-abc123

set -euo pipefail

IMAGE_TAG="${1:-}"

APP_NAME="taskflow"

PORT="${PORT:-8000}"

if [[ -z "$IMAGE_TAG" ]]; then

echo "Usage: $0 "

exit 1

fi

echo "[deploy] pulling $IMAGE_TAG"

docker pull "$IMAGE_TAG"

Create a network once; ignore if it exists

docker network create app_net >/dev/null 2>&1 || true

echo "[deploy] stopping old container (if any)"

docker rm -f "$APP_NAME" >/dev/null 2>&1 || true

echo "[deploy] starting new container"

docker run -d \

--name "$APP_NAME" \

--restart unless-stopped \

--network app_net \

-p 8000:8000 \

"$IMAGE_TAG"

Health check

echo "[deploy] waiting for health endpoint..."

for i in {1..20}; do

if curl -fsS "http://127.0.0.1:${PORT}/health" >/dev/null; then

echo "[deploy] healthy"

exit 0

fi

sleep 1

done

echo "[deploy] health check failed; printing logs"

docker logs "$APP_NAME" || true

exit 1


Make it executable on the remote host:

chmod +x deploy.sh


.github/workflows/ci.yml

This GitHub Actions workflow runs tests (if present), builds and pushes the image to GitHub Container Registry (GHCR), then deploys over SSH by invokingdeploy.sh on your server.

name: ci-cd

on:

push:

branches: [ "main" ]

workflow_dispatch: {}

env:

REGISTRY: ghcr.io

IMAGE_NAME: ${{ github.repository }}/taskflow

jobs:

test:

runs-on: ubuntu-latest

steps:

  • uses: actions/checkout@v4

  • uses: actions/setup-python@v5

with:

python-version: "3.11"

  • run: |

python -m venv .venv

source .venv/bin/activate

pip install -r requirements.txt

Install test deps if present

pip install pytest || true

Run tests if tests exist

if ls -1 test*.py tests 2>/dev/null; then

pytest -q

else

echo "No tests found; skipping."

fi

build-and-push:

needs: test

runs-on: ubuntu-latest

permissions:

contents: read

packages: write

steps:

  • uses: actions/checkout@v4

  • name: Log in to GHCR

uses: docker/login-action@v3

with:

registry: ghcr.io

username: ${{ github.actor }}

password: ${{ secrets.GITHUB_TOKEN }}

  • name: Extract short SHA

id: vars

run: echo "SHORT_SHA=GITHUB_OUTPUT

  • name: Build and push

uses: docker/build-push-action@v6

with:

context: .

push: true

tags: |

{{ env.IMAGE_NAME }}:latest

{{ env.IMAGE_NAME }}:main-${{ steps.vars.outputs.SHORT_SHA }}

deploy:

needs: build-and-push

runs-on: ubuntu-latest

if: github.ref == 'refs/heads/main'

steps:

  • name: Prepare image tag

id: vars

run: echo "IMAGE={{ env.IMAGE_NAME }}:main-GITHUB_OUTPUT

  • name: Deploy over SSH

uses: appleboy/ssh-action@v1.0.3

with:

host: ${{ secrets.DEPLOY_HOST }}

username: ${{ secrets.DEPLOY_USER }}

key: ${{ secrets.DEPLOY_KEY }}

script: |

set -e

cd ${{ secrets.DEPLOY_PATH }}

./deploy.sh "${{ steps.vars.outputs.IMAGE }}"


Secrets to set in your repo settings

- DEPLOY_HOST– your server’s hostname or IP
- DEPLOY_USER– SSH user with Docker permissions
- DEPLOY_KEY– private key for that user (read-only to the repo)
- DEPLOY_PATH– directory on the server that containsdeploy.sh

Remote host one-time setup

- Install Docker.
- Copydeploy.shto${DEPLOY_PATH}and make it executable.
- Ensure the SSH user can run Docker (e.g., add todockergroup).

Local Dry Run

You can simulate the build step locally:

docker build -t taskflow:dev .

docker run -p 8000:8000 --rm taskflow:dev


# 

Clarification Table
| Stage | What Happens | Claude’s Contribution | Outcome |
| --- | --- | --- | --- |
| Test | Install deps, run pytest if tests exist | Tighten assertions, add missing tests, explain failures | Failing code never ships |
| Build | Container image from Dockerfile | Suggest slimmer base images, multi-stage builds, health check endpoints | Repeatable runtime |
| Push | Tag and publish to registry | Enforce semantic tags, generate release notes | Deterministic artifact |
| Deploy | Remote script pulls tag and restarts container | Propose safe backoff, health checks, rollback command | Predictable rollout |
| Observe | Health probe and logs | Summarize logs, propose alerts and metrics | Faster incident response |

You now have a clean CI/CD path that anyone on your team can understand at a glance. Tests gate changes, the container ensures consistent runtime, and a tiny deploy script provides safe, idempotent rollouts with health checks. Claude’s role is to keep this loop tight: summarizing diffs into release notes, proposing safer deploy logic, and generating tests when features change. In the next section, you’ll extend this deployment with configurable environments—dev, staging, and production—with Claude helping you manage secrets, configuration drift, and promotion policies.

## 7.6 Lessons Learned and Improvements
Every deployment pipeline teaches its own lessons. Working through a Claude-guided CI/CD setup demonstrates how powerful automation becomes when paired with reasoning intelligence. This final section revisits what worked, what can be refined, and how to continuously evolve your build–test–deploy loop with Claude as an ever-present development partner. The goal is not just to have a functional pipeline, but one that is self-documenting, reliable, and adaptable—qualities Claude is uniquely positioned to reinforce.

Concept Development

The CI/CD pipeline you built in the previous section follows a modern DevOps principle: automate everything that can fail silently. Each automation step—testing, containerizing, deploying—serves as a defense against human error. Yet, the integration of Claude into this loop elevates it beyond a mechanical process. Claude adds cognitive automation: the ability to reason about changes, detect patterns, and propose improvements before failures reach production.

The lessons can be summarized around four pillars of maturity:

1. Consistency Over Speed: The fastest pipeline is worthless if it produces inconsistent outcomes. Claude helps maintain naming conventions, synchronize Docker tags, and enforce coding standards across environments.
2. Test Depth Matters: Unit tests are good; semantic tests are better. Claude can analyze API schemas, propose property-based tests, and explain gaps between business logic and specification.
3. Deployment Should Be Observable: Health checks and log collection must be embedded into every rollout. Claude can parse your deployment logs to identify non-fatal but critical patterns (like slow startups or warnings) that humans might miss.
4. Iteration Never Ends: Every pipeline is a living system. Claude’s ability to summarize diffs and generate improvement proposals makes continuous refinement natural, not burdensome.

Hands-On Example: Using Claude for Pipeline Improvement Proposals

After several successful deployments of the TaskFlow API, suppose your logs begin to show longer startup times due to dependency bloat. You can prompt Claude directly to help improve this pipeline step.

Prompt Example

“Claude, our Docker build step takes over two minutes and the image size has grown past 1GB. Please analyze this Dockerfile and suggest optimizations for build speed and image size.”

Claude might respond with structured, context-aware suggestions such as:

- Replace `python:3.11-slim` with a multi-stage build that compiles dependencies in one layer and copies only runtime artifacts to the final image.
- Use `pip install --no-cache-dir` along with a pinned `requirements.txt` to reduce rebuild times.
- Introduce a `.dockerignore` file to exclude unnecessary files like `.git`, tests, and local caches.

The following improved Dockerfile incorporates these changes:

```dockerfile

练习题

What is the purpose of setting ENV PYTHONDONTWRITEBYTECODE=1 in the Dockerfile?

A. To disable Python bytecode generation
B. To enable Python bytecode generation
C. To optimize Python performance
D. To set the Python version

Which command is used to expose port 8000 in the Dockerfile?

A. EXPOSE 8000
B. PORT 8000
C. OPEN 8000
D. LISTEN 8000

Which steps are included in the deploy.sh script for restarting the TaskFlow service? (Select all that apply)

A. Pull the latest image
B. Create a Docker network
C. Run database migrations
D. Remove the old container
E. Start a new container

The docker compose up --build command is used to build and run the Docker Compose configuration locally.

The command to make the deploy.sh script executable on the remote host is ___.

What is the purpose of the health check in the deploy.sh script?

Which GitHub Actions workflow job is responsible for building and pushing the Docker image to GHCR?

A. test
B. build-and-push
C. deploy
D. ci-cd

Which files are required for the Dockerized FastAPI + GitHub Actions + SSH Deploy example? (Select all that apply)

A. app.py
B. requirements.txt
C. Dockerfile
D. deploy.sh
E. .github/workflows/ci.yml

The WORKDIR /app command in the Dockerfile sets the working directory to /app inside the container.

The command to run tests in the GitHub Actions workflow is ___.

What is the role of the requirements.txt file in the Docker setup?

Which command is used to start the TaskFlow service in the deploy.sh script?

A. docker start taskflow
B. docker run -d --name taskflow ...
C. docker compose up
D. docker exec taskflow

Which steps are performed by the GitHub Actions workflow during deployment? (Select all that apply)

A. Run tests
B. Build and push the Docker image
C. Deploy over SSH
D. Install Python dependencies
E. Create a Docker network

The COPY app.py . command in the Dockerfile copies the app.py file from the host machine to the container's working directory.

The command to log in to GHCR in the GitHub Actions workflow is ___.

What is the purpose of the EXPOSE 8000 command in the Dockerfile?

Which command is used to simulate the build step locally?

A. docker build -t taskflow:dev .
B. docker compose up --build
C. docker run -p 8000:8000 --rm taskflow:dev
D. docker pull taskflow:dev

Which of the following are required repository secrets for the GitHub Actions workflow? (Select all that apply)

A. DEPLOY_HOST
B. DEPLOY_USER
C. DEPLOY_KEY
D. DEPLOY_PATH
E. GITHUB_TOKEN

In the Dockerfile, what is the purpose of the EXPOSE 8000 instruction, and how does it relate to API testing concepts?

A. It specifies the port on which the application listens internally, and API tests should verify responses on this port
B. It defines the port for SSH access, which is irrelevant to API testing
C. It sets the default port for Docker networking, but API tests should use random ports
D. It is only a documentation hint and has no effect on container behavior or testing

Which steps in the CI/CD pipeline (ci.yml) ensure deterministic deployments, and how do they relate to FastAPI testing practices?

A. The 'test' job that runs unit tests
B. The 'build-and-push' job that packages the service into a container
C. The step that extracts a short SHA for image tagging
D. The 'deploy' job that pulls the exact image to the target
E. The step that installs pytest in the test environment

The health check in deploy.sh (curl to /health endpoint) verifies that the API meets the requirement of being demonstrably correct under normal conditions, as described in prior knowledge point kp_7_4_001.

The _______ instruction in the Dockerfile copies the application files into the container, which is a prerequisite for _______ tests to execute against the running service.

Explain how the CI/CD pipeline's 'build-and-push' job (ci.yml) supports the principle of consistent runtime environments for API testing.

登录后解锁笔记、知识点解析、AI 问答

立即登录