diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml index d3d86b0..08afed3 100644 --- a/.github/workflows/docker.yaml +++ b/.github/workflows/docker.yaml @@ -4,70 +4,123 @@ on: push: branches: - main + workflow_dispatch: jobs: - make-cache: + rust-checks: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - - name: Make Cache + + - name: Rust Cache uses: Swatinem/rust-cache@v2.7.3 with: - save-if: true cache-all-crates: true - shared-key: tests - - name: Update Toolchain + shared-key: rust-cache + cache-on-failure: true + + - name: Setup Rust run: rustup toolchain install stable --profile minimal --no-self-update - - name: Job + + - name: Check formatting + run: cargo fmt --all -- --check + + - name: Build run: cargo build - Clippy: - needs: make-cache - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Load Cache - uses: Swatinem/rust-cache@v2.7.3 - with: - # save-if: false - shared-key: tests - key: clippy - - name: Update Toolchain - run: rustup toolchain install stable --profile minimal --no-self-update - - name: Job + - name: Run Clippy run: cargo clippy -- -D warnings - build: - needs: - - Clippy + docker-build: + needs: rust-checks runs-on: ubuntu-latest - env: - repo: ${{ github.repository }} - owner: ${{ github.repository_owner }} + permissions: + contents: read + packages: write + env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + steps: - - name: Checkout code + - name: Checkout uses: actions/checkout@v4 + - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 - - - name: Convert to lowercase - id: c2l - run: | - INPUT=${{ env.repo }}; echo "l_repo=${INPUT,,}">>${GITHUB_OUTPUT} - INPUT=${{ env.owner }}; echo "l_owner=${INPUT,,}">>${GITHUB_OUTPUT} - - - name: Login to GitHub Container Registry - uses: docker/login-action@v1 + uses: docker/setup-buildx-action@v3 + with: + platforms: linux/amd64 + buildkitd-flags: --debug + + - name: Cache Docker layers + uses: actions/cache@v3 with: - registry: ghcr.io - username: ${{steps.c2l.outputs.l_owner}} + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx- + + - name: Login to Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Build and push Docker image - uses: docker/build-push-action@v2 + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=raw,value=latest + type=sha,format=long + type=ref,event=branch + labels: | + org.opencontainers.image.title=Shuller Bot + org.opencontainers.image.description=Discord Bot + org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }} + maintainer=towinok + + - name: Build and push + id: docker_build + uses: docker/build-push-action@v5 with: context: . - file: Dockerfile push: true - tags: ghcr.io/${{steps.c2l.outputs.l_repo}}:latest \ No newline at end of file + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: | + type=local,src=/tmp/.buildx-cache + type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache + cache-to: | + type=local,dest=/tmp/.buildx-cache-new,mode=max + type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache,mode=max + platforms: linux/amd64 + provenance: false + outputs: | + type=image,name=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }},push-by-digest=true + type=registry + + - name: Move cache + if: always() + run: | + rm -rf /tmp/.buildx-cache + mv /tmp/.buildx-cache-new /tmp/.buildx-cache + + - name: Export digest + if: success() + run: | + mkdir -p /tmp/digests + digest=$(docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest --format '{{.Digest}}') + echo "DIGEST=$digest" >> $GITHUB_ENV + + - name: Check image size + if: success() + run: | + docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + docker image ls ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + + - name: Echo digest + if: success() + run: echo ${{ env.DIGEST }} diff --git a/Cargo.toml b/Cargo.toml index 77ef7ec..18f3319 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,3 +25,16 @@ strip = true opt-level = 3 lto = true debug = false + +[build] +rustflags = [ + "-C", "target-cpu=native", + "-C", "link-arg=-s", +] + +[target.x86_64-unknown-linux-musl] +rustflags = [ + "-C", "target-cpu=native", + "-C", "link-arg=-s", + "-C", "target-feature=-crt-static", +] diff --git a/Dockerfile b/Dockerfile index f9ff1dc..067f81b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,39 +1,50 @@ FROM rust:alpine AS base -RUN apk add --no-cache musl-dev openssl-dev - -ENV RUSTFLAGS="-C target-feature=-crt-static" - -RUN cargo install sccache -RUN cargo install cargo-chef - -ENV RUSTC_WRAPPER=sccache SCCACHE_DIR=/sccache +# Устанавливаем необходимые зависимости и cargo-chef +RUN apk add --no-cache musl-dev openssl-dev \ + && cargo install cargo-chef + +# Настройка переменных окружения для оптимизации +ENV RUSTFLAGS="-C target-feature=-crt-static -C opt-level=3 -C target-cpu=native -C link-arg=-s" +ENV CARGO_NET_GIT_FETCH_WITH_CLI=true +ENV CARGO_HTTP_MULTIPLEXING=false +ENV CARGO_INCREMENTAL=0 +ENV CARGO_PROFILE_RELEASE_LTO=true +ENV CARGO_PROFILE_RELEASE_CODEGEN_UNITS=1 FROM base AS planner WORKDIR /app COPY . . RUN --mount=type=cache,target=/usr/local/cargo/registry \ - --mount=type=cache,target=$SCCACHE_DIR,sharing=locked \ + --mount=type=cache,target=/usr/local/cargo/git \ cargo chef prepare --recipe-path recipe.json FROM base AS builder - WORKDIR /app COPY --from=planner /app/recipe.json recipe.json + +ARG CARGO_BUILD_JOBS=4 + +# Сборка зависимостей RUN --mount=type=cache,target=/usr/local/cargo/registry \ - --mount=type=cache,target=$SCCACHE_DIR,sharing=locked \ + --mount=type=cache,target=/usr/local/cargo/git \ cargo chef cook --release --recipe-path recipe.json + COPY . . +# Финальная сборка RUN --mount=type=cache,target=/usr/local/cargo/registry \ - --mount=type=cache,target=$SCCACHE_DIR,sharing=locked \ - cargo build --release - + --mount=type=cache,target=/usr/local/cargo/git \ + cargo build --release --jobs ${CARGO_BUILD_JOBS} FROM alpine:latest - WORKDIR /app RUN apk add --no-cache ca-certificates libgcc COPY --from=builder /app/target/release/shuller_bot . + +# Создаем non-root пользователя +RUN addgroup -S appgroup && adduser -S appuser -G appgroup +USER appuser + CMD ["./shuller_bot"]