cargo-contract
cargo-contract copied to clipboard
Some issues with docker images.
https://github.com/paritytech/scripts/tree/master/dockerfiles/contracts-ci-linux Docker is a great feature. This ensures that the files compiled on each platform are the same. But I encountered some problems when I used it. I don't know if I'm not using it the right way.
My compiled command is:
docker run -v /home/xxx/contracts:/builds paritytech/contracts-ci-linux:production cargo contract build
- The generated target directory has incorrect permissions.
After I run docker, my file permissions look like this:
-rw-r--r-- 1 root root 30K Apr 12 02:39 Cargo.lock
-rw-r--r-- 1 myusername myusername 1.3K Apr 10 13:47 Cargo.toml
-rw-r--r-- 1 myusername myusername 21K Apr 10 13:47 lib.rs
drwxr-xr-x 3 root root 4.0K Apr 13 10:32 target
I don't know why the target folder and the Cargo.lock file are owned by root. Does this require some changes to the docker image? Or am I using it in the wrong way?
- No compiled cache When I ran the compile command a second time, I found that it still compiled from scratch and did not make use of the previously compiled files. As you know, compiling from scratch is very slow, and this affects development efficiency.
/cc @TriplEight
- This is a typical thing with docker. Either you should set up your
docker
to run rootles, it should be possible since ~November 2020 or consider usingpodman
, API is similar but the latter is more advanced. Alternatively, you could justchown
the output for your user. - Your cache remains in the container. Consider redirecting it the same way you do with the repo. I've created a bash/fish function that simplifies this for me. You can substitute
podman
fordocker
and it will work. Essentially, it does the following:
podman run --rm -it
-w /shellhere/"$dirname" # runs the container in your current dir, i.e. in the cloned repo
-v "$(pwd)":/shellhere/"$dirname" # shares the current dir with a container
-v /home/"$user"/cache/"$dirname"/:/cache/ # outputs cargo cache to your machine so it can be reused
-e CARGO_HOME=/cache/cargo/ # env variable to redirect the dependencies cache
-e SCCACHE_DIR=/cache/sccache/ # env variable for sccache
-e CARGO_TARGET_DIR=/cache/target/ # cach redirection for the compilation cache
"$@" # your cargo command goes here
@TriplEight Thank you, cache is working well. But the issue of permissions remains unresolved. I am developing redspot and would like to integrate docker compilation. So I can't use podman and I can't use chown to change file permissions. I read the documentation for rust's docker. I found that they do this
$ docker run --rm --user "$(id -u)":"$(id -g)" -v "$PWD":/usr/src/myapp -w /usr/src/myapp rust:1.23.0 cargo build --release
They add --user "$(id -u)":"$(id -g)" to give the generated file the correct permissions. But for cargo contract docker
, when I add --user "$(id -u)":"$(id -g)"
, I get an error:
I'm not sure if the cargo contract dockerfile needs some modification to avoid this problem.
I think I'll need a more full repro here. I.e. from scratch on the clean repo.
@TriplEight You mean how to reproduce the error?
- Create a new contract project. Because the user parameter is used, the permission of files are correct.
docker run --rm \
--user $(id -u):$(id -g) \
-v "$PWD":/usr/src/myapp \
-w /usr/src/myapp \
paritytech/contracts-ci-linux:production \
cargo contract new myapp
- Enter the directory of the contract(here is
myapp
) and try adding the user parameter to compile the contract.
docker run --rm \
--user $(id -u):$(id -g) \
-v "$PWD":/usr/src/myapp \
-w /usr/src/myapp \
paritytech/contracts-ci-linux:production \
cargo contract build
get error:
ERROR: Error invoking `cargo metadata`
Caused by:
`cargo metadata` exited with an error: error: failed to run `rustc` to learn about target-specific information
Caused by:
process didn't exit successfully: `sccache rustc - --crate-name ___ --print=file-names --crate-type bin --crate-type rlib --crate-type dylib --crate-type cdylib --crate-type staticlib --crate-type proc-macro --print=sysroot --print=cfg` (exit code: 2)
--- stderr
sccache: error: Timed out waiting for server startup
Stack backtrace:
0: cargo_contract::crate_metadata::CrateMetadata::collect
1: cargo_contract::cmd::build::execute
2: cargo_contract::cmd::build::BuildCommand::exec
3: cargo_contract::main
4: std::sys_common::backtrace::__rust_begin_short_backtrace
5: std::rt::lang_start::{{closure}}
6: core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once
at /rustc/07e0e2ec268c140e607e1ac7f49f145612d0f597/library/core/src/ops/function.rs:259:13
std::panicking::try::do_call
at /rustc/07e0e2ec268c140e607e1ac7f49f145612d0f597/library/std/src/panicking.rs:379:40
std::panicking::try
at /rustc/07e0e2ec268c140e607e1ac7f49f145612d0f597/library/std/src/panicking.rs:343:19
std::panic::catch_unwind
at /rustc/07e0e2ec268c140e607e1ac7f49f145612d0f597/library/std/src/panic.rs:431:14
std::rt::lang_start_internal
at /rustc/07e0e2ec268c140e607e1ac7f49f145612d0f597/library/std/src/rt.rs:51:25
7: main
8: __libc_start_main
9: _start
- Remove the user parameter, then it compiles successfully. But the permission of the target directory is root.
docker run --rm \
-v "$PWD":/usr/src/myapp \
-w /usr/src/myapp \
paritytech/contracts-ci-linux:production \
cargo contract build
I'm experimenting and so far achieved the following:
- first, it's better running
--user $(id -u ${USER}):$(id -g ${USER})
- next step would be turning off
sccache
and here we'll get to a problem cause, which isdocker run --rm \ --user $(id -u):$(id -g) \ -v "$PWD":/usr/src/myapp \ -w /usr/src/myapp \ paritytech/contracts-ci-linux:production \ -e RUSTC_WRAPPER="" \ cargo contract build
ERROR: Error invoking `cargo metadata` Caused by: `cargo metadata` exited with an error: error: failed to get `anyhow` as a dependency of package `cargo-contract v0.11.1 (/shellhere/cargo-contract)` Caused by: failed to create directory `/cache/cargo/registry/index/github.com-1ecc6299db9ec823` Caused by: Permission denied (os error 13)
It can't create files in your OS. Why? Because --user
creates there a non-root user, which you need. But you're running docker
from root
and passing it a volume from root
as well. And now, a non-root container user sees that the mounted volume has root
access and it can't write to it.
This can't be helped by adding a non-root user to the image (we are working on it, but for a different reason).
The issue is that volume is mounted as root
and it's 7y old.
I see the only legal option: remap the user using userns
@ii-ii-ii does Denis' last comment help you at all, or is this still a problem for you?
@ii-ii-ii does Denis' last comment help you at all, or is this still a problem for you?
There are still some problems. But I solved this problem temporarily by using some ugly way. It is to use chown -R ${id}:${group} ${WORK_DIR}
to change the owner.
Please ask me, happy to help.