-
Notifications
You must be signed in to change notification settings - Fork 198
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add custom docker image support #1193
base: master
Are you sure you want to change the base?
Conversation
cffd56f
to
403e26b
Compare
403e26b
to
34ae07e
Compare
cc @jyn514 if this needs tests, where should they go? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you change this to use a git dependency of rustwide for now so it's possible to test that it works?
src/docbuilder/rustwide_builder.rs
Outdated
@@ -322,14 +330,18 @@ impl RustwideBuilder { | |||
|
|||
let local_storage = tempfile::Builder::new().prefix("docsrs-docs").tempdir()?; | |||
|
|||
let metadata = Metadata::from_crate_root(&build_dir.build_dir())?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, are you sure this is right? I think builds happen in a temporary directory, not in the source directory.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't tested it, but Build::host_source_dir
returns self.dir.source_dir()
so i just made that method public.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You have build_dir here, not source_dir - is that intentional?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately this won't work. source_dir()
is populated during the run()
call (build.rs
=> prepare.rs
), so it's going to be empty where you call it. What we could do instead is to make rustwide's Crate::copy_source_to
method public, copy the source to a temporary directory, fetch the metadata from it, and then delete the temporary directory.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how about a BuildDir::create_or_get_source_dir (or whatever name) which both docs.rs and run() can call so we don't waste cpu cycles moving everything twice
4806164
to
0c7d7e4
Compare
crates/metadata/lib.rs
Outdated
pub fn docker_image(&self) -> Option<String> { | ||
self.docker_image.clone() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's return a borrow here, since it's not dynamic.
pub fn docker_image(&self) -> Option<String> { | |
self.docker_image.clone() | |
pub fn docker_image(&self) -> Option<&str> { | |
self.docker_image.as_ref() |
One potential issue I see here is that we'll run out of disk space on the build server really quickly: right now we have 20 GB free (out of 100 GB) but we'll quickly run out of that if every project has their own dockerfile. The current workaround is to run |
@jyn514 i don't know much about docker storage stuff but I was thinking you would probably want to delete the image right after the build. |
Yup, that would work! Can you add logic for that here? I think |
@jyn514 does the dummy crate need to be built in the custom docker image? |
@devsnek I don't quite follow - the dummy crate doesn't configure a docker image, right? So it should be built in the default image, which is https://github.com/rust-lang/crates-build-env. |
@@ -424,6 +436,11 @@ impl RustwideBuilder { | |||
build_dir.purge()?; | |||
krate.purge_from_cache(&self.workspace)?; | |||
local_storage.close()?; | |||
if let Some(image) = metadata.docker_image() { | |||
std::process::Command::new("docker") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
std::process::Command::new("docker") | |
if image != "rustops/crates-build-env" { | |
std::process::Command::new("docker"); | |
} |
Otherwise someone could DOS the queue by publishing a bunch of crates with crates-build-env set.
Actually, I guess they could do that anyway, crates-build-env isn't special ... we just use it by default, so it will be redownloaded. But if you publish a bunch of crates in a row with the same image, it will redownload the image for each crate.
@pietroalbini what do you think, is that a threat model worth worrying about? It won't break the server, it will just make builds really slow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some other ways to break this:
- Make an enormous (like 100gb) docker image
- Make small images which can download quickly enough to hit docker's new ratelimits
ah yeah that makes sense, I was thinking the cargo.toml of the target crate would somehow be loaded for the dummy crate which makes no sense of course... |
So, my understanding is there are two problems to solve:
The first issue can be fixed with an experimental command,
Then we can sum the size of each layer, and if it's greater than the limit we abort the build with an error. Instead if it is lower than the limit we fetch the image with the To "solve" the rate limiting problem, and to prevent slowing down the queue too much, we could gate using custom Docker image with a false-by-default limit, which we lift only if a crate opens an issue and can't add the dependency to crates-build-env (like the nginx case we had). What do y'all think? For the implementation side I'd move the size check over to Rustwide, doing a breaking change on the |
@@ -424,6 +436,11 @@ impl RustwideBuilder { | |||
build_dir.purge()?; | |||
krate.purge_from_cache(&self.workspace)?; | |||
local_storage.close()?; | |||
if let Some(image) = metadata.docker_image() { | |||
std::process::Command::new("docker") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd move this to rustwide's SandboxImage::purge_from_cache()
.
I really like this idea, that gets us three things:
@devsnek can you add a resource limit for docker images that's disabled by default? It would go in |
@jyn514 do you also want to have size limits for images implemented? |
Sure, size limits seem reasonable - maybe 5 GB to start? |
Fixes #315