I use the following Dockerfile:
FROM alpine
COPY /root/ /
where /root/ contains a single file in root/var/spool/cron/crontabs/root.
If I run docker build ., it builds successfully. However, if I use docker buildx build .
failed to solve with frontend dockerfile.v0: failed to build LLB: cannot copy to non-directory: /tmp/buildkit-mount656587830/var/spool/cron/crontabs
@joshuaavalon is that a symbolic link?
Also, I have tried if /root/ only has /root/a.json, it builds fine. May be it has something to do with nested directories.
Ah! Someone already made an action to get buildx. Ahahaha
I should have done the same.... I building from source
I'm going to be offline all day so can't test this.
But I'll try to reproduce the nested use case
This is actually the same error I get when I try the same command with regular cp. "cp: target '/var/spool/./cron/crontabs' is not a directory" . It's a bit weird case as cron/crontabs is a symlink to a directory (not a file what you might expect from this error). I think it is fair to consider the old behavior as a bug as it may have very unexpected results. I verified that the behavior is consistent with fileop and dockerfile-copy implementations.
The issue appears because in alpine base image, /var/spool/cron/crontabs is a symlink to /etc/crontabs, but in your context you have a directory with matching path. So the correct way to write this instruction would be:
COPY /root/var/spool/cron/crontabs /var/spool/cron/crontabs
or
COPY /root/var/spool/cron/crontabs /etc/crontabs
or just rename the file to /etc/crontabs/root under your context if you want to copy full root.
@tiborvass
I expected as much from overriding a symlink. didnt had the time to test it.
file-ops over symlinks are confusing and tend to fail
Ok, so the rationale for the cp command's design is that the user shall be guaranteed that the copy operation puts files exclusively under the destination directory. Symlinks can point outside of the destination which would break that guarantee. So I'm fine with qualifying the legacy builder's behavior as incorrectly lenient.
In this specific case, I would probably go with the 3rd workaround: renaming the crontab to /etc/crontabs/root in the context.
I'm closing this as buildkit/buildx behaves as intended. Feel free to continue discussing if need be.
@tiborvass any plan to treat the behaviour of the old Docker build as a bug and fix it?
Might break a few people implementations
I have no symlink but have the same issue. The old builder is working as expected, but this does not work:
COPY docker/manager-app/manager/etc/. /etc/
There is no symlinks. The output is:
=> ERROR [builder 4/7] COPY docker/manager-app/manager/etc/ /etc/
------
> [builder 4/7] COPY docker/manager-app/manager/etc/ /etc/:
------
failed to solve with frontend dockerfile.v0: failed to build LLB: cannot copy to non-directory: /var/lib/docker/aufs/mnt/mzdig9xzkf3pg13mr1grvfnvg/etc/service
My folders are organized the following:
â–¾ docker/
â–¾ manager-app/
â–¾ manager/
â–¾ etc/
â–¾ nginx/
nginx.conf
â–¾ php7/
â–¾ conf.d/
custom.ini
php-fpm.conf
â–¾ service/
â–¾ nginx/
run*
â–¾ php-fpm/
run*
Dockerfile
So everything should be ok... But it's not.
The non-directory is in the destination, already inside the image. Eg. if it is not a symlink your case is equivalent to
/tmp # mkdir -p src/services/nginx
/tmp # mkdir -p dest
/tmp # echo aa > dest/services
/tmp # cp -a src/. dest/
cp: target 'dest/./services' is not a directory
Oh, indeed, the services file was existing inside the image, that's why it failed. The old builder was overriding this...
At least if somebody has this kind of issue, he can find an answer here now. Thanks :). (and wow, that quick answer)
Most helpful comment
The non-directory is in the destination, already inside the image. Eg. if it is not a symlink your case is equivalent to