use-ink / cargo-contract

Setup and deployment tool for developing Wasm based smart contracts via ink!
GNU General Public License v3.0
252 stars 120 forks source link

Some issues with docker images. #255

Open ii-ii-ii opened 3 years ago

ii-ii-ii commented 3 years ago

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
  1. 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?

  1. 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.
ascjones commented 3 years ago

/cc @TriplEight

TriplEight commented 3 years ago
  1. 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 using podman, API is similar but the latter is more advanced. Alternatively, you could just chown the output for your user.
  2. 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 for docker 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
ii-ii-ii commented 3 years ago

@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:

image

I'm not sure if the cargo contract dockerfile needs some modification to avoid this problem.

TriplEight commented 3 years ago

I think I'll need a more full repro here. I.e. from scratch on the clean repo.

ii-ii-ii commented 3 years ago

@TriplEight You mean how to reproduce the error?

  1. 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
  2. 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 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

3. 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

TriplEight commented 3 years ago

I'm experimenting and so far achieved the following:

  1. first, it's better running --user $(id -u ${USER}):$(id -g ${USER})
  2. next step would be turning off sccache

    docker 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

    and here we'll get to a problem cause, which is

    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

HCastano commented 3 years ago

@ii-ii-ii does Denis' last comment help you at all, or is this still a problem for you?

ii-ii-ii commented 3 years ago

@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.

TriplEight commented 3 years ago

Please ask me, happy to help.