diff --git a/.gitea/workflows/build-template.yml b/.gitea/workflows/build-template.yml new file mode 100644 index 0000000..06c78d2 --- /dev/null +++ b/.gitea/workflows/build-template.yml @@ -0,0 +1,86 @@ +name: Reusable Build + +on: + workflow_call: + inputs: + registry: + description: "Registry hostname (es: gitea.example.com)" + required: true + type: string + image_name: + description: "Nome completo dell'immagine (es: gitea.example.com/org/app)" + required: true + type: string + image_tag: + description: "Tag fisso da applicare (es: staging, latest)" + required: false + type: string + default: "latest" + dockerfile: + description: "Path del Dockerfile da usare" + required: false + type: string + default: "Dockerfile" + +jobs: + build_image: + runs-on: ubuntu-latest + + permissions: + packages: write + contents: read + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Configura Docker Buildx + uses: docker/setup-buildx-action@v3 + with: + buildkitd-flags: --debug + + - name: Login al registry + uses: docker/login-action@v3 + with: + registry: ${{ inputs.registry }} + username: ${{ secrets.DOCKER_LOGIN_USERNAME }} + password: ${{ secrets.DOCKER_LOGIN_TOKEN }} + + - name: Genera metadata Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ inputs.image_name }} + tags: | + type=ref,event=tag + type=raw,value=${{ inputs.image_tag }} + labels: | + org.opencontainers.image.title=learn + org.opencontainers.image.description=Applicazione Rails/Laravel + org.opencontainers.image.vendor=Procne SRL + + - name: Create dummy .npmrc_secret + run: touch ./.npmrc_secret + + - name: Build e Push immagine + uses: docker/build-push-action@v5 + with: + context: . + file: ${{ inputs.dockerfile }} + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=registry,ref=${{ inputs.image_name }}:buildcache + cache-to: type=registry,ref=${{ inputs.image_name }}:buildcache,mode=max + secret-files: | + npmrc=./.npmrc_secret + + - name: Riepilogo build + run: | + echo "=== Build completata ===" + echo "Immagine: ${{ inputs.image_name }}" + echo "Tag: ${{ inputs.image_tag }}" + echo "Tags generati:" + echo "${{ steps.meta.outputs.tags }}" + echo "" + echo "La cache è stata salvata su: ${{ inputs.image_name }}:buildcache" diff --git a/.gitea/workflows/staging.yml b/.gitea/workflows/staging.yml new file mode 100644 index 0000000..2dc75ce --- /dev/null +++ b/.gitea/workflows/staging.yml @@ -0,0 +1,16 @@ +name: Staging Build + +on: + push: + branches: + - main + - master + +jobs: + build: + uses: ./.gitea/workflows/build-template.yml + with: + registry: gitea.mrcdare.org + image_name: gitea.mrcdare.org/marco.dare/learn + image_tag: staging + secrets: inherit diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..46865bd --- /dev/null +++ b/Dockerfile @@ -0,0 +1,76 @@ +# syntax=docker/dockerfile:1 +# check=error=true + +ARG RUBY_VERSION=3.3.6 +ARG RUBY_ABI_VERSION=3.3.0 +ARG NODE_VERSION=22 +FROM docker.io/library/ruby:$RUBY_VERSION-slim AS base + +WORKDIR /rails + +RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt,sharing=locked \ + apt-get update -qq && \ + apt-get install --no-install-recommends -y curl libjemalloc2 libvips postgresql-client + +ENV RAILS_ENV="production" \ + BUNDLE_DEPLOYMENT="1" \ + BUNDLE_PATH="/usr/local/bundle" \ + BUNDLE_WITHOUT="development:test" + +# ============================================================================== +# Throw-away build stage to reduce size of final image +# ============================================================================== +ARG RUBY_ABI_VERSION +ARG NODE_VERSION +FROM base AS build + +RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt,sharing=locked \ + --mount=type=cache,target=/root/.npm \ + apt-get update -qq && \ + curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION}.x | bash - && \ + apt-get install --no-install-recommends -y build-essential git libpq-dev libyaml-dev pkg-config nodejs && \ + npm install -g yarn + +# Gems: cache downloaded .gem files separately from extracted gems. +# The cache mount target matches the bundler download cache for the Ruby ABI version. +COPY Gemfile Gemfile.lock ./ + +RUN --mount=type=cache,id=bundler,target=/usr/local/bundle/ruby/${RUBY_ABI_VERSION}/cache \ + bundle install && \ + rm -rf "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \ + bundle exec bootsnap precompile --gemfile + +# Node modules: cache yarn downloads independently of app code. +# .npmrc is injected via secret at build time — no need to COPY it. +COPY package.json yarn.lock ./ +RUN --mount=type=cache,id=yarn,target=/yarn-cache \ + --mount=type=secret,id=npmrc,target=/rails/.npmrc \ + yarn install --frozen-lockfile --cache-folder /yarn-cache + +COPY . . + +RUN bundle exec bootsnap precompile app/ lib/ + +RUN ./bin/vite build + +RUN rm -rf node_modules tmp/cache vendor/javascript spec test + +# ============================================================================== +# Final stage for app image +# ============================================================================== +FROM base + +COPY --from=build "${BUNDLE_PATH}" "${BUNDLE_PATH}" +COPY --from=build /rails /rails + +RUN groupadd --system --gid 1000 rails && \ + useradd rails --uid 1000 --gid 1000 --create-home --shell /bin/bash && \ + chown -R rails:rails db log storage tmp +USER 1000:1000 + +ENTRYPOINT ["/rails/bin/docker-entrypoint.prod.sh"] + +EXPOSE 3000 +CMD ["./bin/rails", "server", "-b", "0.0.0.0", "-p", "3000"]