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
Improve experience in nested container environments #497
Improve experience in nested container environments #497
Conversation
d7ec773
to
10a32cf
Compare
Codecov Report
@@ Coverage Diff @@
## main #497 +/- ##
==========================================
+ Coverage 69.67% 70.17% +0.50%
==========================================
Files 21 21
Lines 2048 2116 +68
==========================================
+ Hits 1427 1485 +58
- Misses 497 500 +3
- Partials 124 131 +7
📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more |
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 left a few minor comments before testing the changes locally.
Could you please resolve the go.mod conflicts too?
@baez90 btw, just to let you know I started yesterday as an @AtomicJar employee maintaining the open source projects of the testcontainers family, so full-time dedication to this amazing community!! |
I'll resolve the conflicts in the evening. Congratulations to the new position! 🎉 I'm excited to hear that the community got such a great supporter with you! Wish you all the best with this new challenge 😊 |
Yeah, many times codecov complains about a line not being touched, even on dependabot PRs, which makes me think if it's adding more noise than value. So I'd delegate a final approval on the coverage to a human |
ea47fe7
to
45436fa
Compare
Don't know how to fix the patch coverage issue but at least to overall coverage is fixed 🙂 |
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 added a few ultra-minor comments, but other than that LGTM
I noticed there are changes that could have been sent in a separate PR (replacement of ioutil/io, go version in module files, indents, filepath for the win, usage of constants in tests, better assertions, better usage of t.Testing functions -helpers,environment vars-, increased timeouts) but I'm pretty sure they we re discovered and needed while working in the nested checks.
For further PRs I'd appreciate if we could send those small chunks separately, so that the review of the original feature (nested container environments) could be done faster 🙏
Thanks again for your contribution to make tc-go great!
Makefile
Outdated
@@ -11,6 +11,22 @@ test-unit: | |||
--packages="./..." \ | |||
-- -coverprofile=cover.txt | |||
|
|||
.PHONY: test-nested-container |
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.
Nit
.PHONY: test-nested-container | |
.PHONY: test-unit-nested |
Makefile
Outdated
@@ -1,6 +1,6 @@ | |||
|
|||
.PHONY: test-all | |||
test-all: tools test-unit test-e2e | |||
test-all: tools test-unit test-e2e test-nested-container |
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.
Nit
test-all: tools test-unit test-e2e test-nested-container | |
test-all: tools test-unit test-e2e test-unit-nested |
@@ -264,3 +265,12 @@ func (c *ContainerRequest) validateMounts() error { | |||
} | |||
return nil | |||
} | |||
|
|||
func RunningInContainer() bool { | |||
return fileExists("/.dockerenv") || fileExists("/run/.containerenv") |
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 guess these checks are coupled to traditional LXC containers (.dockerenv) or Podman ones (.containerenv), right?
Do you foresee any other container type, or even any other source to check if running in a container?
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.
On the same hand, this method is used only for testing. Do we still want to expose it as public API?
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.
If I remember correctly it is not only used in testing but also to determine if the container environment information should be fetched.
I was wondering as well if it makes sense to expose this but I thought it could be useful and it's not a huge 'burden' to maintain 😄
Regarding other indicators: I'm not sure how Docker is handling the same with Windows containers so there might be another check in the future to cover these as well (although supporting Windows containers will be fun anyway if this is something that should be done in the future) but apart from that I hope /run/.containerenv
is not only used by Podman but by all other container providers apart from 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.
Let's be careful about .dockerenv
. To my last knowledge, this is an undocumented implementation detail of Docker and not necessarily a stable indicator. There is some discussion around this on SO, which sadly does not provide a better alternative: https://superuser.com/questions/1021834/what-are-dockerenv-and-dockerinit
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 am ware, although Podman explicitly adopted this with their /run/.containerenv
flag.
Surely this is not the greatest solution but a fairly easy one and for instance also used in tc-dotnet
.
Furthermore the SO link you attached mentions a moby repository where they added the exact same behavior so it seems this flag is considered stable enough by the Docker guys 😄
An alternative approach could be to not use these flags at all but to check if /etc/hostname
is mounted (by checking the /proc/self/mountinfo
) and if so try to get the container ID from the mount root.
Both solutions are not perfect, I'm open for suggestions
I'll have a look at your nits probably tomorrow, thanks for your feedback! Sorry about "mixing" up the PR, I tried to separate the changes in multiple commits to improve the review flow e.g. all the |
No worries at all, I totally understand it and I can imagine myself adding commits on top as you did while finding "things". So not a problem :) I mentioned because we are tying to have a better internal review process, and things like that would improve our performance 😅 |
I am joining this PR as a
There are other reasons why the mount won't work, most notably a remote Docker daemon. With making them host-path relative are you specifically talking about the Docker-Socket-Mounting scenario? I believe solving this can be a bigger headache than clearly not supporting it and using copy-to-container mechanisms instead. |
Thanks @kiview, I was planing to articulate exactly this into a separate issue, maybe it makes sense to add it here as a reference. |
Thanks @kiview for the feedback. Of course this could as well left out but I'm hitting this scenario a lot in the last time and always building custom images only to work around this issue in certain circumstances means a significant loss of performance in comparison to just re-map the source if possible - especially because you've to build the image no matter if running locally or in the CI. I don't intent to solve this issue altogether (like also taking care of volume mounts....) but in this special scenario it...doesn't seem like such a headache to be honest? 😅 |
@baez90 Thanks for the explanation, I was initially missing the meaning of |
😄 yeah I mean there are always things that can be improved and some corner cases that are hard to circumvent e.g. if a user has a...socket-to-TCP proxy to - for whatever reason - not use the TCP connection directly it'll be nearly impossible to detect this but for such scenarios it's still possible to fallback to copy-to-container or introduce an option to explicitly disable the mapping later. Also there are of course still scenarios that could be covered to further improve the DX but this PR is already blown up too much 😄 so probably something for later |
db8b292
to
c7f8515
Compare
What's the current state of this? Is it missing something? |
@baez90 after moving compose to a separate module, this PR got into conflicts. Are you still interested on it? Otherwise we could close it and eventually submit a new one. Thanks! |
I'm actually wondering if it would not make sense to re-create this PR instead of trying to rebase it. |
Hey @baez90 I'm tempted to close this PR because of
Just to let you know, there is a WIP PR for improving podman support here: #1251 |
Yeah, I won't be able to progress on that in the close future I'm afraid, thanks! |
What does this PR do?
Container env detection
Currently testcontainers-go detects only nested Docker environments (no check for
/run.container
for Podman) and from my understanding it only checks for the default gateway of the default network to use this for port mappings.This PR refactors the current behavior to also consider Podman environments and to detect its own container ID from the
/etc/hostname
mount (both Docker and Podman are doing this somehow similar with a tmpfs mount from a directory that has the container ID in the mount root path.Bind mount remapping
The library now detects if it is running in a container (with a local Docker daemon i.e. with a Docker socket, not a TCP/HTTP connection) and if a developer attempts to use a bind mount in this setting it will try to map the source path to a host path.
Considering the following example:
/home/ci/work/1234/
on the hostdocker run --rm -i -v /home/ci/work/1234:/work -v /var/run/docker.sock:/var/run/docker.sock:ro -w /work ...
/work/testdata/my-config.toml
to a test containertc-go
detects it is running in container environment and that the path/work/
is actually part of a bind mounttc-go
"re-maps" the mount source/work/testdata/my-config.toml
to/home/ci/work/1234/testdata/my-config.toml
/etc/test/my-config.toml
to a test containertc-go
detects it is running in container environment and that the path/etc/test/my-config.toml
might not be available if mounted to another container and returns an errorThere are some corner cases that are currently not yet taken care of like: