commit 05bfaf692acf1433a638cbc2c0eb4f7bce11e725 Author: yorgei Date: Fri Apr 4 00:58:13 2025 +0000 add first doc diff --git a/gitea-docker-cicd/README.md b/gitea-docker-cicd/README.md new file mode 100644 index 0000000..7002258 --- /dev/null +++ b/gitea-docker-cicd/README.md @@ -0,0 +1,371 @@ +# Gitea Docker CI/CD Workflow Setup + +This guide outlines how to set up a local CI/CD workflow using Gitea running in Docker. The goals are: + +* Use Gitea as the primary Git repository. +* Optionally mirror repositories to GitHub. +* Build Docker images for selected repositories (e.g., NextJS applications) using Gitea Runners. +* Host the built Docker images in a local Docker Registry. +* Automatically update running Docker containers when new images are available. + +## Prerequisites + +* Docker installed and running on your host machine. +* Docker Compose installed. +* A running Gitea instance, preferably managed via Docker Compose. + +## Goal Architecture + +1. **Developer:** Pushes code to a Gitea repository. +2. **Gitea:** + * (Optional/Manual) Mirrors the repository to GitHub. + * Triggers a Gitea Action workflow on push/tag. +3. **Gitea Runner (Docker):** + * Picks up the workflow job. + * Checks out the code. + * Builds a Docker image using Docker-in-Docker or by mounting the host's Docker socket. + * Pushes the built image to a Local Docker Registry. +4. **Local Docker Registry (Docker):** Stores the built application images. +5. **Watchtower (or similar tool - Docker):** Monitors the Local Docker Registry for new image versions and automatically updates the running application containers. +6. **Application Container (Docker):** Runs the application (e.g., NextJS app) using the image from the Local Docker Registry. + +--- + +## Step 1: Set up Gitea <-> GitHub Synchronization (Mirroring) + +Configure Gitea to push changes to a corresponding GitHub repository. + +1. **Generate a GitHub Personal Access Token (PAT):** + * Go to GitHub Settings -> Developer settings -> Personal access tokens -> Tokens (classic) or Fine-grained tokens. + * Generate a token with `repo` scope (or specific repository write access). Copy the token securely. +2. **Configure Mirroring in Gitea:** + * Navigate to your Gitea repository. + * Go to `Settings` -> `Repository` -> `Mirror Settings`. + * Click `Add Push Mirror`. + * **Git Remote Repository URL:** Enter the HTTPS URL of your GitHub repo (e.g., `https://github.com/your-username/your-repo.git`). + * **Authorization:** + * **Username:** Your GitHub username. + * **Password/Token:** Paste the GitHub PAT. + * **Sync Interval:** Set the automatic sync frequency (e.g., `1h`, `8h`) or leave blank/`0` for manual sync only. + * Click `Add Mirror Repository`. +3. **Manual Push (Optional):** Click the "Synchronize Now" button next to the mirror entry to push immediately. + +*Note: Gitea becomes the source of truth. Changes made directly on GitHub won't sync back automatically without a pull mirror setup.* + +--- + +## Step 2: Set up a Local Docker Registry + +This container stores the Docker images built by the runner. + +1. **Add Registry Service to `docker-compose.yml`:** + + ```yaml + # In your docker-compose.yml + version: '3.7' + + services: + # ... your other services (like Gitea) ... + + registry: + image: registry:2 + container_name: local-docker-registry + ports: + # Map to a host port, e.g., 5000. Change if needed. + - "5000:5000" + volumes: + # Persist registry data + - ./registry-data:/var/lib/registry + restart: always + networks: + # Use a common network if Gitea/Runner need to access it by name + - your_shared_network # Optional: Replace with your network name + + volumes: + registry-data: + # ... other volumes ... + + networks: + your_shared_network: # Optional: Define if not already defined + external: false # Or true if defined elsewhere + ``` + +2. **Run the Registry:** + + ```bash + docker-compose -f up -d registry + ``` + +3. **Configure Docker Daemon for Insecure Registry:** + * Your Docker daemon needs to trust this HTTP registry. Edit `/etc/docker/daemon.json` (create if it doesn't exist): + + ```json + { + "insecure-registries" : ["YOUR_HOST_IP:5000"] + } + ``` + * **Important:** Replace `YOUR_HOST_IP` with the actual network IP address of the machine running the registry (e.g., `192.168.1.100`). **Do not use `localhost` or `127.0.0.1`** if the runner is in a separate container. + * Restart the Docker daemon: + + ```bash + sudo systemctl restart docker + # Or equivalent command for your OS (e.g., restart Docker Desktop) + ``` + * *Security Note: This uses HTTP and is insecure. For sensitive environments, configure TLS for the registry.* + +--- + +## Step 3: Set up Gitea Runners + +Runners execute Gitea Actions workflows. + +1. **Enable Actions in Gitea:** + * Ensure Actions are enabled in your Gitea instance's `app.ini` configuration file: + + ```ini + [actions] + ENABLED = true + ``` + * Restart your Gitea container after changing `app.ini`. + +2. **Get Runner Registration Token:** + * In Gitea, go to `Site Administration` -> `Runners` (for global runners) or Repository `Settings` -> `Actions` -> `Runners` (for repository-specific runners). + * Note the `Registration Token`. + +3. **Add Runner Service to `docker-compose.yml`:** + * This example mounts the host's Docker socket. + + ```yaml + # In your docker-compose.yml + version: '3.7' + + services: + # ... your gitea, registry services ... + + gitea-runner: + image: gitea/act_runner:latest # Check for the latest official image tag + container_name: gitea-runner + environment: + # Get these from Gitea Admin/Repo Settings -> Actions -> Runners + GITEA_INSTANCE_URL: http://your_gitea_url:3000 # URL to your Gitea instance + GITEA_RUNNER_REGISTRATION_TOKEN: YOUR_REGISTRATION_TOKEN_HERE + GITEA_RUNNER_NAME: my-docker-runner # Optional name + # Define runner capabilities. 'docker' is used in the example workflow. + # Adjust labels as needed for your workflows. + GITEA_RUNNER_LABELS: docker:docker://host.docker.internal/var/run/docker.sock,ubuntu-latest:docker://node:18-bullseye + volumes: + # Mount Docker socket from host - allows runner to use host Docker + - /var/run/docker.sock:/var/run/docker.sock + # Persist runner config + - ./gitea-runner-data:/data + restart: always + networks: + - your_shared_network # Ensure it can reach Gitea and the Registry + + volumes: + gitea-runner-data: + # ... other volumes ... + + networks: + your_shared_network: # Define if not already defined + # ... + ``` + * **Replace:** `http://your_gitea_url:3000` with your Gitea instance URL and `YOUR_REGISTRATION_TOKEN_HERE` with the token from Gitea. + * **Labels:** Ensure the `GITEA_RUNNER_LABELS` match the `runs-on:` directive in your workflow files. + +4. **Run the Runner:** + + ```bash + docker-compose -f up -d gitea-runner + ``` + +5. **Verify Registration:** Check the `Runners` section in Gitea (Admin or Repository Settings) to confirm the runner is registered and idle. + +--- + +## Step 4: Create Gitea Actions Workflow for Building and Pushing + +Define the build process for your application (e.g., NextJS). + +1. **Create a `Dockerfile`:** + * Add a `Dockerfile` to the root of your application's repository. Example for NextJS (multi-stage): + + ```dockerfile + # Stage 1: Build the application + FROM node:18-alpine AS builder + WORKDIR /app + COPY package*.json ./ + RUN npm install + COPY . . + # Example: Set build-time args if needed + # ARG NEXT_PUBLIC_API_URL + # ENV NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL + RUN npm run build + + # Stage 2: Production image + FROM node:18-alpine + WORKDIR /app + ENV NODE_ENV=production + # Uncomment the following line in case you want to disable telemetry during runtime. + # ENV NEXT_TELEMETRY_DISABLED 1 + COPY --from=builder /app/public ./public + # Automatically leverage output traces to reduce image size + # [https://nextjs.org/docs/advanced-features/output-file-tracing](https://nextjs.org/docs/advanced-features/output-file-tracing) + COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ + COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static + + # Expose the port Next.js runs on + EXPOSE 3000 + + ENV PORT 3000 + + # Optional: Run as non-root user + # RUN addgroup --system --gid 1001 nodejs + # RUN adduser --system --uid 1001 nextjs + # USER nextjs + + # Command to run the application + CMD ["node", "server.js"] + ``` + +2. **Create the Workflow File:** + * In your repository, create `.gitea/workflows/build-push.yaml`: + + ```yaml + name: Build and Push Docker Image + + on: + push: + branches: + - main # Trigger on pushes to the main branch + tags: + - 'v*.*.*' # Trigger on version tags like v1.0.0 + + jobs: + build-and-push: + # Use a runner label defined in your runner's environment variables + runs-on: docker + steps: + - name: Checkout Code + uses: actions/checkout@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + # Optional: Login step if your registry requires authentication + # - name: Log in to local registry + # uses: docker/login-action@v2 + # with: + # registry: YOUR_HOST_IP:5000 # Use the same IP as in daemon.json + # username: ${{ secrets.REGISTRY_USERNAME }} # Store credentials in Gitea secrets + # password: ${{ secrets.REGISTRY_PASSWORD }} # Store credentials in Gitea secrets + + - name: Determine Image Tag + id: meta + run: | + # Use Git tag if present, otherwise use 'latest' for default branch + if [[ ${GITHUB_REF} == refs/tags/* ]]; then + TAG=${GITHUB_REF#refs/tags/} + else + TAG=latest + fi + echo "tag=${TAG}" >> $GITHUB_OUTPUT + echo "Using tag: ${TAG}" + + - name: Build and Push Docker Image + uses: docker/build-push-action@v4 + with: + context: . + file: ./Dockerfile + push: true + # IMPORTANT: Tag format is REGISTRY_HOST:PORT/IMAGE_NAME:TAG + tags: YOUR_HOST_IP:5000/your-app-image-name:${{ steps.meta.outputs.tag }} + # Optional: Add build arguments + # build-args: | + # ARG_NAME=value + cache-from: type=gha # Optional: Enable build cache + cache-to: type=gha,mode=max # Optional: Enable build cache + ``` + * **Replace:** + * `YOUR_HOST_IP:5000` with your registry's IP and port. + * `your-app-image-name` with your desired image name. + * **`runs-on: docker`**: Ensure this matches a label on your Gitea Runner. + * **Secrets:** If using registry authentication, store credentials (`REGISTRY_USERNAME`, `REGISTRY_PASSWORD`) in the Gitea repository's `Settings` -> `Secrets`. + +3. **Commit and Push:** Add `.gitea/workflows/build-push.yaml` and your `Dockerfile` to the repository, commit, and push to Gitea. + +4. **Monitor Workflow:** Check the `Actions` tab in your Gitea repository to view the workflow execution status. + +--- + +## Step 5: Automatically Update Containers with Watchtower + +Use Watchtower to monitor the local registry and redeploy containers when a new image is available. + +1. **Add Application and Watchtower Services to `docker-compose.yml`:** + + ```yaml + # In your docker-compose.yml + version: '3.7' + + services: + # ... your gitea, registry, runner services ... + + # Your Application container (Example: NextJS) + my-app: + # IMPORTANT: Use the full image path from your local registry + image: YOUR_HOST_IP:5000/your-app-image-name:latest # Watchtower tracks this tag + container_name: my-app-container + ports: + - "8080:3000" # Map host port 8080 to container port 3000 (adjust as needed) + restart: always + networks: + - your_shared_network + labels: + # Required label for Watchtower to manage this container when using --label-enable + - "com.centurylinklabs.watchtower.enable=true" + + # Watchtower service + watchtower: + image: containrrr/watchtower:latest + container_name: watchtower + volumes: + # Mount Docker socket to allow Watchtower to manage other containers + - /var/run/docker.sock:/var/run/docker.sock + # Optional: Mount Docker config if registry requires authentication + # Make sure docker login has been run on the host first + # - $HOME/.docker/config.json:/config.json + # Check every 5 minutes (300s), remove old images, only update containers with the specific label + command: --cleanup --label-enable --interval 300 + restart: always + networks: + - your_shared_network # Needs network access if registry needs authentication + + networks: + your_shared_network: # Define if not already defined + # ... + ``` + * **Replace:** `YOUR_HOST_IP:5000/your-app-image-name:latest` with your registry IP, port, image name, and the tag Watchtower should monitor (usually `latest`). + * **`image:` directive:** Ensure your application service (`my-app`) uses the full image path from your local registry. + * **`labels:`:** Add the `com.centurylinklabs.watchtower.enable=true` label to any container you want Watchtower to auto-update. + * **`command:`:** Use `--label-enable` for safety, so Watchtower only touches labeled containers. Adjust `--interval` as needed. + +2. **Run Application and Watchtower:** + + ```bash + # Bring up the application and Watchtower (and others if not running) + docker-compose -f up -d + ``` + +--- + +## Summary Workflow + +1. Push code (matching `on:` criteria in workflow) to Gitea. +2. Gitea triggers the Actions workflow (`build-push.yaml`). +3. Gitea Runner executes the job: checks out code, builds image, pushes tagged image (e.g., `:latest` or `:v1.x.x`) to the local registry (`YOUR_HOST_IP:5000`). +4. Watchtower (running via Docker) polls the registry. +5. If Watchtower detects a new image digest for the tag specified in your application container's `image:` directive (e.g., `:latest`), it pulls the new image and redeploys the application container using the updated image. +6. (Optional) Gitea pushes code changes to GitHub via the configured mirror. + +You now have an automated build and deployment pipeline hosted locally with Gitea! Remember to replace all placeholders (like `YOUR_HOST_IP`, image names, network names, tokens) with your actual values. \ No newline at end of file