diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..b8a1dcb --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,36 @@ +# Build, test and deploy moresleep with the javaBin platform pipeline. +# +# Pull requests: build + test, regenerate terraform/ from app.yaml, plan, and +# post the plan with an AI risk review as a PR comment. Nothing is applied. +# Pushes to master (and manual runs): the same, then apply the reviewed plan, +# build the Docker image, push it to ECR and roll out the ECS service. +# +# How it works: docs/platform.md. Pipeline reference: +# https://github.com/javaBin/platform/blob/main/docs/reusable-workflows.md +name: Deploy + +on: + push: + branches: [master] + pull_request: + workflow_dispatch: + +permissions: + id-token: write # AWS access via GitHub OIDC (no AWS secrets in the repo) + contents: write # the expand step commits regenerated terraform/ to the branch + pull-requests: write # plan + review comment on PRs + +concurrency: + group: deploy-${{ github.ref }} + cancel-in-progress: false + +jobs: + javabin: + uses: javaBin/platform/.github/workflows/javabin.yml@main + with: + java_version: "21" + # The tests need a real PostgreSQL, the same as docker/postgres sets up. + test_postgres_image: postgres:17 + test_postgres_db: moresleepunit + test_postgres_user: localdevuser + test_postgres_password: localdevuser # throwaway CI database, not a secret diff --git a/Dockerfile b/Dockerfile index 2aef973..4a4833e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,41 +1,31 @@ -# Build: docker build -t moresleep-app:latest . -# Run: docker run --name moresleep-container -p 5000:5000 moresleep-app:latest -# Check localhost:5000 and you should get a homepage -# Stage 1: Build the application +# Platform image: built and pushed to ECR by the javaBin platform pipeline +# (.github/workflows/deploy.yml), run on ECS Fargate. +# +# Configuration comes from environment variables that ECS injects (app.yaml +# `environment:` and `resources.secrets`), so the image holds no secrets and +# needs no SOPS or AWS CLI. The container runs as uid 1000 with a read-only +# root filesystem and a writable /tmp. +# +# Local run: +# docker build -t moresleep . +# docker run --rm -p 8082:8082 -e DBHOST=host.docker.internal moresleep + +# Stage 1: build the jar (tests run in the pipeline's build-jvm job before this) FROM maven:3.9.11-eclipse-temurin-21 AS build WORKDIR /app COPY pom.xml . +RUN mvn --batch-mode --quiet dependency:go-offline COPY src ./src -RUN mvn clean package -Dmaven.test.skip=true +RUN mvn --batch-mode package -Dmaven.test.skip=true -# Stage 2: Create the final runtime image -FROM eclipse-temurin:21-jre-jammy AS final - -# Install SOPS -RUN curl -L -o /usr/local/bin/sops https://github.com/getsops/sops/releases/download/v3.10.2/sops-v3.10.2.linux.amd64 && \ - chmod +x /usr/local/bin/sops - - # Install unzip and curl -RUN apt-get update && \ - apt-get install -y curl unzip && \ - rm -rf /var/lib/apt/lists/* - - # Install AWS CLI v2 -RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "/tmp/awscliv2.zip" && \ - unzip /tmp/awscliv2.zip -d /tmp && \ - /tmp/aws/install && \ - rm -rf /tmp/aws /tmp/awscliv2.zip - -# Set environment variables -ENV DO_FLYWAY_MIGRATION=false +# Stage 2: runtime +FROM eclipse-temurin:21-jre-jammy +# Production settings (port 5000, DO_FLYWAY_MIGRATION=false, ...) come from +# app.yaml. The image keeps the code defaults, so it also works as the local +# dev image (port 8082, migrations on), like the previous :edge image. ENV RUN_FROM_JAR=true - WORKDIR /app COPY --from=build /app/target/moresleep-0.0.1-jar-with-dependencies.jar app.jar -COPY ./conf/.enc.env /app/.enc.env - -# Remove AWS profile from SOPS config to use container's AWS credentials -RUN sed -i 's/sops_kms__list_0__map_aws_profile=javabin/sops_kms__list_0__map_aws_profile=/' /app/.enc.env - -EXPOSE 5000 -ENTRYPOINT ["sops", "exec-env", ".enc.env", "java -jar app.jar"] \ No newline at end of file +USER 1000 +EXPOSE 5000 8082 +ENTRYPOINT ["java", "-XX:MaxRAMPercentage=75", "-jar", "app.jar"] diff --git a/Dockerfile.cdk b/Dockerfile.cdk new file mode 100644 index 0000000..557717d --- /dev/null +++ b/Dockerfile.cdk @@ -0,0 +1,44 @@ +# Image for the OLD CDK stack (moresleepstack / cluster moresleep-test). +# Kept only as the rollback path until the platform cutover is done; the +# platform pipeline builds ./Dockerfile instead. Removed in the cleanup PR. +# Build: docker build -f Dockerfile.cdk -t moresleep-app:latest . +# Run: docker run --name moresleep-container -p 5000:5000 moresleep-app:latest +# Check localhost:5000 and you should get a homepage +# Stage 1: Build the application +FROM maven:3.9.11-eclipse-temurin-21 AS build +WORKDIR /app +COPY pom.xml . +COPY src ./src +RUN mvn clean package -Dmaven.test.skip=true + +# Stage 2: Create the final runtime image +FROM eclipse-temurin:21-jre-jammy AS final + +# Install SOPS +RUN curl -L -o /usr/local/bin/sops https://github.com/getsops/sops/releases/download/v3.10.2/sops-v3.10.2.linux.amd64 && \ + chmod +x /usr/local/bin/sops + + # Install unzip and curl +RUN apt-get update && \ + apt-get install -y curl unzip && \ + rm -rf /var/lib/apt/lists/* + + # Install AWS CLI v2 +RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "/tmp/awscliv2.zip" && \ + unzip /tmp/awscliv2.zip -d /tmp && \ + /tmp/aws/install && \ + rm -rf /tmp/aws /tmp/awscliv2.zip + +# Set environment variables +ENV DO_FLYWAY_MIGRATION=false +ENV RUN_FROM_JAR=true + +WORKDIR /app +COPY --from=build /app/target/moresleep-0.0.1-jar-with-dependencies.jar app.jar +COPY ./conf/.enc.env /app/.enc.env + +# Remove AWS profile from SOPS config to use container's AWS credentials +RUN sed -i 's/sops_kms__list_0__map_aws_profile=javabin/sops_kms__list_0__map_aws_profile=/' /app/.enc.env + +EXPOSE 5000 +ENTRYPOINT ["sops", "exec-env", ".enc.env", "java -jar app.jar"] \ No newline at end of file diff --git a/cdk/lib/moresleep-stack.ts b/cdk/lib/moresleep-stack.ts index d6e0df1..3a8320c 100644 --- a/cdk/lib/moresleep-stack.ts +++ b/cdk/lib/moresleep-stack.ts @@ -43,7 +43,7 @@ export class MoresleepStack extends cdk.Stack { console.log('Current working directory:', process.cwd()); taskDefinition.addContainer('web', { - image: ecs.ContainerImage.fromAsset('../', { file: 'Dockerfile' }), + image: ecs.ContainerImage.fromAsset('../', { file: 'Dockerfile.cdk' }), // SOPS image; ./Dockerfile is the platform image portMappings: [{ containerPort: port }], logging: new ecs.AwsLogDriver({ streamPrefix: 'web' }), diff --git a/run-local.sh b/run-local.sh index fd6a99c..2a37912 100755 --- a/run-local.sh +++ b/run-local.sh @@ -6,8 +6,8 @@ PATH_PREFIX="$1" echo "Setting PATH_PREFIX to: '$PATH_PREFIX'" -# Build the Docker image -docker build -t moresleep-app:latest . +# Build the SOPS image used by the old CDK stack (decrypts conf/.enc.env with your AWS profile) +docker build -f Dockerfile.cdk -t moresleep-app:latest . # Run the container with AWS credentials mounted docker run --rm -it \