Skip to content

Commit 8e8615b

Browse files
bors[bot]urso
andauthored
Merge #387
387: Docker in docker r=reitermarkus a=urso When using docker-in-docker, for example in dev or CI containers, one normally gives access to the host docker environment to the parent container. If the container spins up another child container, and wishes to share a directory, one needs to compute the correct paths from view of the host system. ### How it Works If the environment variable `CROSS_DOCKER_IN_DOCKER=true`, we call `docker inspect $HOSTNAME`, to learn about details of the current container. The `Mounts` field contains information about all mounts from the host into the current container. The `GraphDriver` field gives us information about the storage driver and the location of the contains root directory on the host system. Based on these information we compute a table of all container mounts (`source->destination`). When starting a child container we adapt all paths to be mounted, that have a prefix in the table, to start with source. For example when mounting a dev containers `/usr/local/cargo` directory, we will actually mount `/var/lib/docker/overlay2/<parent container id>/merged/usr/local/cargo`. If the project itself is mounted into the parent container, we will not use the overlay directory, but find the project path on the host system. ### Limitations Finding the mount point for the containers root directory is only implemented for the overlayfs2 storage driver. In order to access the parent containers rust setup, the child container mounts the parents overlayfs. The parent must not be stopped before the child container, as the overlayfs can not be unmounted correctly by docker if the child container still accesses it. Co-authored-by: Steffen Siering <steffen.siering@gmail.com>
2 parents 47f325a + f2c70b3 commit 8e8615b

File tree

7 files changed

+337
-11
lines changed

7 files changed

+337
-11
lines changed

Cargo.lock

Lines changed: 24 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ semver = "0.9"
2121
toml = "0.5"
2222
which = { version = "3.1.0", default_features = false }
2323
shell-escape = "0.1.4"
24+
serde_json = "1.0.48"
2425

2526
[target.'cfg(not(windows))'.dependencies]
2627
nix = "0.15"

README.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,49 @@ RUN dpkg --add-architecture arm64 && \
123123
$ docker build -t my/image:tag path/to/where/the/Dockerfile/resides
124124
```
125125

126+
### Docker in Docker
127+
128+
When running `cross` from inside a docker container, `cross` needs access to
129+
the hosts docker daemon itself. This is normally achieved by mounting the
130+
docker daemons socket `/var/run/docker.sock`. For example:
131+
132+
```
133+
$ docker run -v /var/run/docker.sock:/var/run/docker.sock -v .:/project \
134+
-w /project my/development-image:tag cross build --target mips64-unknown-linux-gnuabi64
135+
```
136+
137+
The image running `cross` requires the rust development tools to be installed.
138+
139+
With this setup `cross` must find and mount the correct host paths into the
140+
container used for cross compilation. This includes the original project directory as
141+
well as the root path of the parent container to give access to the rust build
142+
tools.
143+
144+
To inform `cross` that it is running inside a container set `CROSS_DOCKER_IN_DOCKER=true`.
145+
146+
A development or CI container can be created like this:
147+
148+
```
149+
FROM rust:1
150+
151+
# set CROSS_DOCKER_IN_DOCKER to inform `cross` that it is executed from within a container
152+
ENV CROSS_DOCKER_IN_DOCKER=true
153+
154+
# install `cross`
155+
RUN cargo install cross
156+
157+
...
158+
159+
```
160+
161+
**Limitations**: Finding the mount point for the containers root directory is
162+
currently only available for the overlayfs2 storage driver. In order to access
163+
the parent containers rust setup, the child container mounts the parents
164+
overlayfs. The parent must not be stopped before the child container, as the
165+
overlayfs can not be unmounted correctly by Docker if the child container still
166+
accesses it.
167+
168+
126169
### Passing environment variables into the build environment
127170

128171
By default, `cross` does not pass any environment variables into the build

azure-pipelines.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ jobs:
7979
- bash: echo "##vso[task.setvariable variable=TAG]${BUILD_SOURCEBRANCH##refs/tags/}"
8080
displayName: Set TAG Variable
8181
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags/')
82+
- bash: cargo test
83+
displayName: Run unit tests
84+
timeoutInMinutes: 5
8285
- bash: ./build-docker-image.sh "${TARGET}"
8386
displayName: Build Docker Image
8487
timeoutInMinutes: 360

src/cli.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
1+
use std::str::FromStr;
12
use std::{env, path::PathBuf};
23

3-
use crate::Target;
44
use crate::cargo::Subcommand;
55
use crate::rustc::TargetList;
6+
use crate::Target;
67

78
pub struct Args {
89
pub all: Vec<String>,
910
pub subcommand: Option<Subcommand>,
1011
pub target: Option<Target>,
1112
pub target_dir: Option<PathBuf>,
13+
pub docker_in_docker: bool,
1214
}
1315

1416
pub fn parse(target_list: &TargetList) -> Args {
@@ -27,7 +29,10 @@ pub fn parse(target_list: &TargetList) -> Args {
2729
all.push(t);
2830
}
2931
} else if arg.starts_with("--target=") {
30-
target = arg.splitn(2, '=').nth(1).map(|s| Target::from(&*s, target_list));
32+
target = arg
33+
.splitn(2, '=')
34+
.nth(1)
35+
.map(|s| Target::from(&*s, target_list));
3136
all.push(arg);
3237
} else if arg == "--target-dir" {
3338
all.push(arg);
@@ -41,19 +46,24 @@ pub fn parse(target_list: &TargetList) -> Args {
4146
all.push(format!("--target-dir=/target"));
4247
}
4348
} else {
44-
if !arg.starts_with('-') && sc.is_none() {
45-
sc = Some(Subcommand::from(arg.as_ref()));
46-
}
49+
if !arg.starts_with('-') && sc.is_none() {
50+
sc = Some(Subcommand::from(arg.as_ref()));
51+
}
4752

48-
all.push(arg.to_string());
53+
all.push(arg.to_string());
4954
}
5055
}
5156
}
5257

58+
let docker_in_docker = env::var("CROSS_DOCKER_IN_DOCKER")
59+
.map(|s| bool::from_str(&s).unwrap_or_default())
60+
.unwrap_or_default();
61+
5362
Args {
5463
all,
5564
subcommand: sc,
5665
target,
5766
target_dir,
67+
docker_in_docker,
5868
}
5969
}

0 commit comments

Comments
 (0)