Eugene-Usachev
@Eugene-Usachev

Почему в Docker собирается не тот Rust?

Вопрос звучит странно, но я даже не способен по-другому это описать. Я решил протестировать, как мой проект работает на других платформах, для этого я использовал Docker. Я изучаю Rust относительно недолго, так что воспользовался помощью гугла для написания Dockerfile.

Dockerfile

FROM rust:latest as build

RUN USER=root cargo new --bin test-tcp
WORKDIR /test-tcp

COPY ./Cargo.lock ./Cargo.lock
COPY ./Cargo.toml ./Cargo.toml

RUN cargo build --release
RUN rm src/*.rs

COPY ./src ./src

# Build for release.
RUN cargo build --release

FROM debian:buster-slim

COPY --from=build /test-tcp/target/release/test-tcp /usr/src/test-tcp

CMD ["/usr/src/test-tcp"]



Cargo.toml

[package]
name = "test-tcp"
version = "0.1.0"
edition = "2021"

[dependencies]
tokio = { version = "1.29.1", features = ["full"] }
mio = "0.8.8"
net2 = "0.2.39"
ahash = "0.8.3"



Дальше я пробую запустить проект. Структура проекта (примерная, можете спросить больше в комментариях)
bench2
--src
----main.rs
--Cargo.toml
--Cargo.lock
--Dockerfile


Теперь самое интересное. Если я запускаю свой код через терминал, как обычно, я вижу нужный результат (старт бенчмарков). Однако когда я пробую запустить Dockerfile, я вижу сборку и совершенно неожиданный результат в консоле
Hello, world!


Я проверил через поиск по проекту и у меня в проекте нигде нет этой строки! Что я сделал не так?
  • Вопрос задан
  • 166 просмотров
Решения вопроса 2
bingo347
@bingo347
Crazy on performance...
FROM rust:latest as build

WORKDIR /test-tcp

COPY ./Cargo.lock ./Cargo.lock
COPY ./Cargo.toml ./Cargo.toml
COPY ./src ./src

RUN cargo build --release

FROM debian:buster-slim

COPY --from=build /test-tcp/target/release/test-tcp /usr/src/test-tcp

CMD ["/usr/src/test-tcp"]

Проблема в том, что в докере Вы создаете пустой проект из шаблона cargo
RUN USER=root cargo new --bin test-tcp
и компилируете его, потом копируете src
Да, там есть еще один билд после этого, но я попробовал собрать Ваш Dockerfile у себя, и получил на втором билде результат инкрементальной сборки без изменений. То есть cargo не увидел, что папка src поменялась.
Ответ написан
vabka
@vabka
Токсичный шарпист
Как уже выше сказали - cargo не увидел, что src поменялись и не стал собирать заново.
Определяет он, что файл изменился по дате изменения файла. Если дата изменения файла меньше либо равна дате компиляции, то повторной компиляции не будет.
Чтобы обновить дату изменения файла - достаточно сделать touch main.rs после первой сборки.
В docker появился docker init, который сам делает корректный dockerfile - так что в принципе уже и не нужно руками dockerfile писать.
Генерирует он примерно такое для компиляции (зачем так - описано в комментариях):
ARG RUST_VERSION=1.71.0
ARG APP_NAME=project
FROM rust:${RUST_VERSION}-slim-bullseye AS build
ARG APP_NAME
WORKDIR /app

# Build the application.
# Leverage a cache mount to /usr/local/cargo/registry/
# for downloaded dependencies and a cache mount to /app/target/ for
# compiled dependencies which will speed up subsequent builds.
# Leverage a bind mount to the src directory to avoid having to copy the
# source code into the container. Once built, copy the executable to an
# output directory before the cache mounted /app/target is unmounted.
RUN --mount=type=bind,source=src,target=src \
    --mount=type=bind,source=Cargo.toml,target=Cargo.toml \
    --mount=type=bind,source=Cargo.lock,target=Cargo.lock \
    --mount=type=cache,target=/app/target/ \
    --mount=type=cache,target=/usr/local/cargo/registry/ \
    <<EOF
set -e
cargo build --locked --release
cp ./target/release/$APP_NAME /bin/server
EOF


Ещё можно попробовать написать так (этим пользовался я раньше):
# FROM, Установка rust и прочих зависимостей
# ...

RUN cargo new /app
COPY app/Cargo.toml /app/

# This step compiles only our dependencies and saves them in a layer. This is the most impactful time savings
# Note the use of --mount=type=cache. On subsequent runs, we'll have the crates already downloaded
WORKDIR /app
RUN --mount=type=cache,target=/usr/local/cargo/registry cargo build --release

COPY ./app /app

# touch нужен, чтобы изменить дату изменения файла
RUN --mount=type=cache,target=/usr/local/cargo/registry \
  set -e; \
  touch /app/src/main.rs; \
  cargo build --release;


Оба варианта позволяют активно использовать фичи кэширования в Docker, чтобы не выкачивать все зависимости и не перекомпилировать их при каждой сборке образа.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы