From 46ec47aa2d943f0d2f543577e98c06d458ad7f9f Mon Sep 17 00:00:00 2001 From: Daisuke Date: Tue, 30 Dec 2025 16:37:09 +0900 Subject: [PATCH] Add explicit Forgejo deployment structure with artifact build pipeline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Introduce clear directory separation for docker, infra, ci, and config - Add CloudFormation pipeline for S3 → CodeBuild → ECR - Implement explicit artifact build script for flat deployment zip - Provide example runtime configuration and ignore secrets --- .gitignore | 2 + README.md | 30 +++++++ ci/buildspec.yml | 18 ++++ config/app.ini.example | 6 ++ docker/Dockerfile | 13 +++ docker/entrypoint.sh | 50 +++++++++++ infra/cfn/forgejo.yaml | 181 ++++++++++++++++++++++++++++++++++++++ scripts/build-artifact.sh | 23 +++++ 8 files changed, 323 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 ci/buildspec.yml create mode 100644 config/app.ini.example create mode 100644 docker/Dockerfile create mode 100755 docker/entrypoint.sh create mode 100644 infra/cfn/forgejo.yaml create mode 100755 scripts/build-artifact.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0fb75ee --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +artifacts/* +config/app.ini diff --git a/README.md b/README.md new file mode 100644 index 0000000..00d3feb --- /dev/null +++ b/README.md @@ -0,0 +1,30 @@ +## Purpose +This repository contains deployment sources for running Forgejo on AWS ECS. +Infrastructure is managed using CloudFormation, and application artifacts are +built explicitly for use in CI/CD pipelines. + +## Structure +- docker/ + Container definition for Forgejo (Dockerfile and entrypoint) + +- config/ + Runtime configuration templates + (actual configuration is injected at runtime) + +- ci/ + CI/CD definitions (e.g. AWS CodeBuild buildspec) + +- infra/ + Infrastructure as Code (CloudFormation templates) + +- artifacts/ + Build artifacts used as inputs for deployment pipelines + +- scripts/ + Helper scripts for building deployment artifacts + +## Artifact Build +Deployment artifacts are built explicitly using a helper script. + +```sh +scripts/build-artifact.sh diff --git a/ci/buildspec.yml b/ci/buildspec.yml new file mode 100644 index 0000000..0c1b314 --- /dev/null +++ b/ci/buildspec.yml @@ -0,0 +1,18 @@ +version: 0.2 +phases: + pre_build: + commands: + - set -e + - ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text) + - REPOSITORY_URI=${ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/forgejo-repository + - aws ecr get-login-password --region ${AWS_DEFAULT_REGION} | docker login --username AWS --password-stdin ${REPOSITORY_URI} + - GIT_TAG=$(date +%s) + build: + commands: + - set -e + - docker build -t ${REPOSITORY_URI}:${GIT_TAG} -t ${REPOSITORY_URI}:latest . + post_build: + commands: + - set -e + - docker push ${REPOSITORY_URI}:${GIT_TAG} + - docker push ${REPOSITORY_URI}:latest diff --git a/config/app.ini.example b/config/app.ini.example new file mode 100644 index 0000000..a7c2fea --- /dev/null +++ b/config/app.ini.example @@ -0,0 +1,6 @@ +[storage] +STORAGE_TYPE = minio +MINIO_USE_SSL = true +MINIO_ENDPOINT = s3.amazonaws.com +MINIO_BUCKET = forgejo-bucket +MINIO_LOCATION = ap-northeast-1 diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..57fc950 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,13 @@ +FROM codeberg.org/forgejo/forgejo:11-rootless + +# Copy your custom app.ini from the build context into a safe location not masked by EFS. +COPY app.ini /defaults/app.ini + +# Copy the custom entrypoint script. +COPY entrypoint.sh /entrypoint.sh + +# Set the custom entrypoint. +ENTRYPOINT ["/entrypoint.sh"] + +# Optionally, retain a CMD if needed. +CMD [] diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh new file mode 100755 index 0000000..9a17551 --- /dev/null +++ b/docker/entrypoint.sh @@ -0,0 +1,50 @@ +#!/bin/sh +set -e + +# Define the target configuration file path where Forgejo (or Gitea) expects it. +CONFIG_DIR="/var/lib/gitea/custom/conf" +CONFIG_FILE="${CONFIG_DIR}/app.ini" + +# Define the path to the default configuration file bundled in the image. +DEFAULT_CONFIG="/defaults/app.ini" + +# Read the optional environment variable to force the configuration update. +# Set FORCE_COPY_APP_CONF=true to force overwriting the configuration file. +FORCE_COPY=${FORCE_COPY_APP_CONF:-false} + +echo "Starting container initialization..." + +# If the force option is enabled, remove the existing configuration file (if any) +if [ "$FORCE_COPY" = "true" ]; then + echo "Force option enabled. Removing any existing configuration file at ${CONFIG_FILE}..." + rm -f "$CONFIG_FILE" +fi + +# If the configuration file does not exist, prepopulate it from the default copy. +if [ ! -f "$CONFIG_FILE" ]; then + echo "Configuration file not found at ${CONFIG_FILE}." + echo "Prepopulating the EFS volume with the default configuration." + + # Make sure the configuration directory exists. + mkdir -p "$CONFIG_DIR" + + # Copy the default configuration file into the mounted volume. + cp "$DEFAULT_CONFIG" "$CONFIG_FILE" + + # Set proper ownership and permissions. + # Replace '1000:1000' with the UID:GID used by Forgejo if different. + chown 1000:1000 "$CONFIG_FILE" + chmod 644 "$CONFIG_FILE" + + echo "Prepopulation complete. Configuration is now available at ${CONFIG_FILE}." +else + echo "Configuration file already exists at ${CONFIG_FILE}. Skipping prepopulation." +fi + +# Optionally, log the first few lines of the configuration file for verification. +echo "Current configuration (first few lines):" +head -n 10 "$CONFIG_FILE" + +# Hand over execution to the original entrypoint. +# The official Forgejo image typically uses the entrypoint at '/usr/local/bin/docker-entrypoint.sh' +exec /usr/local/bin/docker-entrypoint.sh "$@" diff --git a/infra/cfn/forgejo.yaml b/infra/cfn/forgejo.yaml new file mode 100644 index 0000000..db2626d --- /dev/null +++ b/infra/cfn/forgejo.yaml @@ -0,0 +1,181 @@ +AWSTemplateFormatVersion: "2010-09-09" +Description: S3 -> CodePipeline -> CodeBuild(ARM) -> ECR pipeline for Forgejo + +Parameters: + SourceBucketName: + Type: String + Default: forgejo-source-bucket + + SourceObjectKey: + Type: String + Default: forgejo-source.zip + + ForgejoRepositoryName: + Type: String + Default: forgejo-repository + +Resources: + + # S3 Bucket (Source) + SourceBucket: + Type: AWS::S3::Bucket + Properties: + BucketName: !Sub "ap-northeast-1-${AWS::AccountId}-${SourceBucketName}" + Tags: + - Key: Project + Value: Git-server + VersioningConfiguration: + Status: Enabled + + # ECR Repository + ForgejoRepository: + Type: AWS::ECR::Repository + Properties: + RepositoryName: !Ref ForgejoRepositoryName + ImageScanningConfiguration: + ScanOnPush: true + + # IAM Role for CodeBuild + CodeBuildRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Principal: + Service: codebuild.amazonaws.com + Action: sts:AssumeRole + Policies: + - PolicyName: CodeBuildPolicy + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Resource: "*" + - Effect: Allow + Action: + - ecr:GetAuthorizationToken + Resource: "*" + - Effect: Allow + Action: + - ecr:BatchCheckLayerAvailability + - ecr:InitiateLayerUpload + - ecr:UploadLayerPart + - ecr:CompleteLayerUpload + - ecr:PutImage + Resource: + - !Sub "arn:aws:ecr:ap-northeast-1:${AWS::AccountId}:repository/forgejo-repository" + - Effect: Allow + Action: + - s3:GetObject + - s3:PutObject + - s3:ListBucket + Resource: + - !Sub "arn:aws:s3:::codebuild-ap-northeast-1-${AWS::AccountId}-input-bucket" + - !Sub "arn:aws:s3:::codebuild-ap-northeast-1-${AWS::AccountId}-input-bucket/*" + - !Sub "arn:aws:s3:::ap-northeast-1-${AWS::AccountId}-${SourceBucketName}" + - !Sub "arn:aws:s3:::ap-northeast-1-${AWS::AccountId}-${SourceBucketName}/*" + + + # CodeBuild Project (ARM) + ForgejoBuildProject: + Type: AWS::CodeBuild::Project + Properties: + ServiceRole: !GetAtt CodeBuildRole.Arn + Artifacts: + Type: CODEPIPELINE + Environment: + Type: ARM_CONTAINER + ComputeType: BUILD_GENERAL1_MEDIUM + Image: aws/codebuild/amazonlinux2-aarch64-standard:3.0 + PrivilegedMode: true + EnvironmentVariables: + - Name: ECR_REPOSITORY + Value: !Ref ForgejoRepositoryName + Source: + Type: CODEPIPELINE + TimeoutInMinutes: 30 + + # IAM Role for CodePipeline + CodePipelineRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Principal: + Service: codepipeline.amazonaws.com + Action: sts:AssumeRole + Policies: + - PolicyName: CodePipelinePolicy + PolicyDocument: + Version: '2012-10-17' + Statement: + # Permissions for accessing the artifacts bucket + - Effect: Allow + Action: + - s3:GetObject + - s3:GetObjectVersion + - s3:PutObject + - s3:ListBucket + - s3:GetBucketLocation + - s3:GetBucketVersioning + Resource: + - !Sub "arn:aws:s3:::codebuild-ap-northeast-1-${AWS::AccountId}-input-bucket" + - !Sub "arn:aws:s3:::codebuild-ap-northeast-1-${AWS::AccountId}-input-bucket/*" + - !Sub "arn:aws:s3:::ap-northeast-1-${AWS::AccountId}-${SourceBucketName}" + - !Sub "arn:aws:s3:::ap-northeast-1-${AWS::AccountId}-${SourceBucketName}/*" + # Permissions for CodeBuild (if used) + - Effect: Allow + Action: + - codebuild:StartBuild + - codebuild:BatchGetBuilds + Resource: "*" + # Permissions for manual approval actions in CodePipeline + - Effect: Allow + Action: + - codepipeline:PutApprovalResult + Resource: "*" + + # CodePipeline + ForgejoPipeline: + Type: AWS::CodePipeline::Pipeline + Properties: + PipelineType: V2 + RoleArn: !GetAtt CodePipelineRole.Arn + ArtifactStore: + Type: S3 + Location: !Sub "codebuild-ap-northeast-1-${AWS::AccountId}-input-bucket" + Stages: + - Name: Source + Actions: + - Name: S3Source + ActionTypeId: + Category: Source + Owner: AWS + Provider: S3 + Version: "1" + Configuration: + S3Bucket: !Ref SourceBucket + S3ObjectKey: !Ref SourceObjectKey + PollForSourceChanges: true + OutputArtifacts: + - Name: SourceOutput + - Name: Build + Actions: + - Name: BuildImage + ActionTypeId: + Category: Build + Owner: AWS + Provider: CodeBuild + Version: "1" + InputArtifacts: + - Name: SourceOutput + Configuration: + ProjectName: !Ref ForgejoBuildProject diff --git a/scripts/build-artifact.sh b/scripts/build-artifact.sh new file mode 100755 index 0000000..b596fda --- /dev/null +++ b/scripts/build-artifact.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)" +ARTIFACT_DIR="${ROOT_DIR}/artifacts" +ZIP_PATH="${ARTIFACT_DIR}/forgejo-source.zip" + +mkdir -p "${ARTIFACT_DIR}" + +tmpdir="$(mktemp -d)" +trap 'rm -rf "${tmpdir}"' EXIT + +cp "${ROOT_DIR}/docker/Dockerfile" "${tmpdir}/Dockerfile" +cp "${ROOT_DIR}/docker/entrypoint.sh" "${tmpdir}/entrypoint.sh" +cp "${ROOT_DIR}/config/app.ini" "${tmpdir}/app.ini" +cp "${ROOT_DIR}/ci/buildspec.yml" "${tmpdir}/buildspec.yml" + +( + cd "${tmpdir}" + zip -r "${ZIP_PATH}" . +) + +echo "Artifact created: ${ZIP_PATH}"