Skip to content
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

docker_container's with 'platform' always recreated. #654

Closed
pinko-fowle opened this issue Jun 22, 2023 · 8 comments · Fixed by #705
Closed

docker_container's with 'platform' always recreated. #654

pinko-fowle opened this issue Jun 22, 2023 · 8 comments · Fixed by #705
Labels
bug Something isn't working docker-plain plain Docker (no swarm, no compose, no stack)

Comments

@pinko-fowle
Copy link

pinko-fowle commented Jun 22, 2023

SUMMARY

Whenever a docker_container task has a platform param, it is recreated, even if nothing else has changed.

ISSUE TYPE
  • Bug Report
COMPONENT NAME

community.docker.docker_container

ANSIBLE VERSION
ansible [core 2.15.0]
  config file = /Users/pinko/src/st-up-ansible/ansible.cfg
  configured module search path = ['/Users/pinko/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /opt/homebrew/Cellar/ansible/8.0.0/libexec/lib/python3.11/site-packages/ansible
  ansible collection location = /Users/pinko/.ansible/collections:/usr/share/ansible/collections
  executable location = /opt/homebrew/bin/ansible
  python version = 3.11.4 (main, Jun  7 2023, 00:34:59) [Clang 14.0.3 (clang-1403.0.22.14.1)] (/opt/homebrew/Cellar/ansible/8.0.0/libexec/bin/python3.11)
  jinja version = 3.1.2
  libyaml = True
COLLECTION VERSION
# /opt/homebrew/Cellar/ansible/8.0.0/libexec/lib/python3.11/site-packages/ansible_collections
Collection       Version
---------------- -------
community.docker 3.4.6
CONFIGURATION
INTERPRETER_PYTHON(/Users/pinko/src/st-up-ansible/ansible.cfg) = /usr/local/bin/python3
OS / ENVIRONMENT

Host & target: the same MacOS Ventura 13.4 macbook pro. Docker Desktop 4.20.1.

STEPS TO REPRODUCE

Rerunning the following task will recreate the container each time:

- name: run mysql57 container
  docker_container:
    name: mysql-5.7
    image: mysql:5.7-oracle
    env:
        MYSQL_ROOT_PASSWORD: abracadabra42
    platform: linux/amd64
EXPECTED RESULTS

This task should create the container the first time & then not recreate it the next time, if ran again.

ACTUAL RESULTS

This task recreates the containers.

changed: [localhost] => {"changed": true, "container": {"AppArmorProfile": "", "Args": ["mysqld"], "Config": {"AttachStderr": true, "AttachStdin": false, "AttachStdout": true, "Cmd": ["mysqld"], "Domainname": "", "Entrypoint": ["docker-entrypoint.sh"], "Env": ["MYSQL_ROOT_PASSWORD=abracadabra42", "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "GOSU_VERSION=1.16", "MYSQL_MAJOR=5.7", "MYSQL_VERSION=5.7.42-1.el7", "MYSQL_SHELL_VERSION=8.0.33-1.el7"], "ExposedPorts": {"3306/tcp": {}, "33060/tcp": {}}, "Hostname": "a7c9414c909a", "Image": "mysql:5.7-oracle", "Labels": {}, "OnBuild": null, "OpenStdin": false, "StdinOnce": false, "Tty": false, "User": "", "Volumes": {"/var/lib/mysql": {}}, "WorkingDir": ""}, "Created": "2023-06-22T20:35:46.427559919Z", "Driver": "overlay2", "ExecIDs": null, "GraphDriver": {"Data": {"LowerDir": "/var/lib/docker/overlay2/45745aa99c786575cabe2b93f5b210056493802f324f0f4385fcc9b36ea30d27-init/diff:/var/lib/docker/overlay2/1160abd8b58b7cb425eef7769e8f03e60d961ad695f1b99b79937a4c3c2d1ea0/diff:/var/lib/docker/overlay2/35aa0ad571a32011dd9f2d732145485aee6b4089cbe14a70b65a0cb6b3b548e7/diff:/var/lib/docker/overlay2/1f6bcb064708ac650c7058b92f4179c704d0980b8bd2ff9e9b8c94c761155291/diff:/var/lib/docker/overlay2/5b58748242940170ea1a52a9921deb216cafa5e5b4fe8cd41005cc6b7801b6d1/diff:/var/lib/docker/overlay2/1e46a50997bb4b4807e585505e0a4098543707fefd2b0c15dad517bb1cb9ce2d/diff:/var/lib/docker/overlay2/64c828a1a3b65ebd102758983d199e6ae065c8e39c532fdd208948c9e21f1549/diff:/var/lib/docker/overlay2/38fb91e37fb4718c4e243568bd63ae5aa211fb162081fef6d3f3db0d379d4f57/diff:/var/lib/docker/overlay2/f63541c4d89dec98be37dd8a26b0b083ce8ddd181d595575a52a7d7be077af45/diff:/var/lib/docker/overlay2/080256a67321e855a02388bb815b6b216668816166b0c3fe43e5c289bf371d81/diff:/var/lib/docker/overlay2/e40f1f999792d9b4ca24a9b33d766e7bfa292ca8824715c436382a59ba5d4860/diff:/var/lib/docker/overlay2/ec60cbb812b5efcbb5ab56810d747a9f413fcd196c033dba4d7d75666a6cb259/diff", "MergedDir": "/var/lib/docker/overlay2/45745aa99c786575cabe2b93f5b210056493802f324f0f4385fcc9b36ea30d27/merged", "UpperDir": "/var/lib/docker/overlay2/45745aa99c786575cabe2b93f5b210056493802f324f0f4385fcc9b36ea30d27/diff", "WorkDir": "/var/lib/docker/overlay2/45745aa99c786575cabe2b93f5b210056493802f324f0f4385fcc9b36ea30d27/work"}, "Name": "overlay2"}, "HostConfig": {"AutoRemove": false, "Binds": null, "BlkioDeviceReadBps": null, "BlkioDeviceReadIOps": null, "BlkioDeviceWriteBps": null, "BlkioDeviceWriteIOps": null, "BlkioWeight": 0, "BlkioWeightDevice": null, "CapAdd": null, "CapDrop": null, "Cgroup": "", "CgroupParent": "", "CgroupnsMode": "private", "ConsoleSize": [0, 0], "ContainerIDFile": "", "CpuCount": 0, "CpuPercent": 0, "CpuPeriod": 0, "CpuQuota": 0, "CpuRealtimePeriod": 0, "CpuRealtimeRuntime": 0, "CpuShares": 0, "CpusetCpus": "", "CpusetMems": "", "DeviceCgroupRules": null, "DeviceRequests": null, "Devices": null, "Dns": null, "DnsOptions": null, "DnsSearch": null, "ExtraHosts": null, "GroupAdd": null, "IOMaximumBandwidth": 0, "IOMaximumIOps": 0, "IpcMode": "private", "Isolation": "", "Links": null, "LogConfig": {"Config": {}, "Type": "json-file"}, "MaskedPaths": ["/proc/asound", "/proc/acpi", "/proc/kcore", "/proc/keys", "/proc/latency_stats", "/proc/timer_list", "/proc/timer_stats", "/proc/sched_debug", "/proc/scsi", "/sys/firmware"], "Memory": 0, "MemoryReservation": 0, "MemorySwap": 0, "MemorySwappiness": null, "NanoCpus": 0, "NetworkMode": "default", "OomKillDisable": null, "OomScoreAdj": 0, "PidMode": "", "PidsLimit": null, "PortBindings": null, "Privileged": false, "PublishAllPorts": false, "ReadonlyPaths": ["/proc/bus", "/proc/fs", "/proc/irq", "/proc/sys", "/proc/sysrq-trigger"], "ReadonlyRootfs": false, "RestartPolicy": {"MaximumRetryCount": 0, "Name": ""}, "Runtime": "runc", "SecurityOpt": null, "ShmSize": 67108864, "UTSMode": "", "Ulimits": null, "UsernsMode": "", "VolumeDriver": "", "VolumesFrom": null}, "HostnamePath": "/var/lib/docker/containers/a7c9414c909af28c0951a0bc990cd98910ec24992d9a3f9fef970132cb746478/hostname", "HostsPath": "/var/lib/docker/containers/a7c9414c909af28c0951a0bc990cd98910ec24992d9a3f9fef970132cb746478/hosts", "Id": "a7c9414c909af28c0951a0bc990cd98910ec24992d9a3f9fef970132cb746478", "Image": "sha256:2be84dd575ee2ecdb186dc43a9cd951890a764d2cefbd31a72cdf4410c43a2d0", "LogPath": "/var/lib/docker/containers/a7c9414c909af28c0951a0bc990cd98910ec24992d9a3f9fef970132cb746478/a7c9414c909af28c0951a0bc990cd98910ec24992d9a3f9fef970132cb746478-json.log", "MountLabel": "", "Mounts": [{"Destination": "/var/lib/mysql", "Driver": "local", "Mode": "", "Name": "f6bcf77b737a211926eaae64da3d1a30e78b5a89a6049e007d2e912c278822e5", "Propagation": "", "RW": true, "Source": "/var/lib/docker/volumes/f6bcf77b737a211926eaae64da3d1a30e78b5a89a6049e007d2e912c278822e5/_data", "Type": "volume"}], "Name": "/mysql-5.7", "NetworkSettings": {"Bridge": "", "EndpointID": "0e251c7c7a33bfdd5bbb60b79d6da21564647673053d4c53b158febc3acf83aa", "Gateway": "172.17.0.1", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "HairpinMode": false, "IPAddress": "172.17.0.4", "IPPrefixLen": 16, "IPv6Gateway": "", "LinkLocalIPv6Address": "", "LinkLocalIPv6PrefixLen": 0, "MacAddress": "02:42:ac:11:00:04", "Networks": {"bridge": {"Aliases": null, "DriverOpts": null, "EndpointID": "0e251c7c7a33bfdd5bbb60b79d6da21564647673053d4c53b158febc3acf83aa", "Gateway": "172.17.0.1", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "IPAMConfig": null, "IPAddress": "172.17.0.4", "IPPrefixLen": 16, "IPv6Gateway": "", "Links": null, "MacAddress": "02:42:ac:11:00:04", "NetworkID": "17e97f7948aaa041cc6dbbfecc82dc7f7edfcaaa478dffe88d47cc19f9c9b1c1"}}, "Ports": {"3306/tcp": null, "33060/tcp": null}, "SandboxID": "6c761d1f4678374a3e54aee37484c6afabd1fceefb2777dbb4254f4501282194", "SandboxKey": "/var/run/docker/netns/6c761d1f4678", "SecondaryIPAddresses": null, "SecondaryIPv6Addresses": null}, "Path": "docker-entrypoint.sh", "Platform": "linux", "ProcessLabel": "", "ResolvConfPath": "/var/lib/docker/containers/a7c9414c909af28c0951a0bc990cd98910ec24992d9a3f9fef970132cb746478/resolv.conf", "RestartCount": 0, "State": {"Dead": false, "Error": "", "ExitCode": 0, "FinishedAt": "0001-01-01T00:00:00Z", "OOMKilled": false, "Paused": false, "Pid": 6939, "Restarting": false, "Running": true, "StartedAt": "2023-06-22T20:35:46.640927919Z", "Status": "running"}}}
WORKAROUND
  • If I use community.docker.docker_image to download the image with the desired platform first, docker_container will use that image. This lets me omit the platform parameter, avoiding this bug.

  • Docs have a note of caution about platform & valid workaround, using comparison options:

Please note that inspecting the container does not always return the exact platform string used to create the container. This can cause idempotency to break for this module. Use the comparisons option with platform: ignore to prevent accidental recreation of the container due to this.

None the less, this bug is a very surprising behavior & we have had developers lose development machine data because of it.

@felixfontein
Copy link
Collaborator

Try running the module with --diff to see what the module thinks its changing.

From the return value I guess the module sees that the container's platform is linux and not linux/amd64, and thus re-creates the container.

@felixfontein felixfontein added bug Something isn't working docker-plain plain Docker (no swarm, no compose, no stack) labels Jun 22, 2023
@pinko-fowle
Copy link
Author

Got it in one!

 {
-    "platform": "linux"
+    "platform": "linux/amd64"
 }

Thanks for the fast follow-up. I think this is still a bug, not user error, but I'm not sure if there's something simple/obvious I should be doing.

@felixfontein
Copy link
Collaborator

The module doesn't know that linux and linux/amd64 is the same. You need to supply linux to the module if Docker claims that's the platform.

@pinko-fowle
Copy link
Author

linux doesn't work on the first run, because Docker tries to get the linux/armv8 image, which doesn't exist. platform: linux/amd64 is required to work the first time. but then it will blow away the container every time after.

i've tried poking through the source here to understand how docker_container reads the platform out, but i haven't made much progress. if you happen to know & can point me at this, that'd be great. i'm hoping maybe we can find some better routes to understanding that this is in fact a linux/amd64 image that's running. if i use docker image inspect on the image, it shows the arch is indeed amd64; maybe there's some way to read that information in & use it. but i'm still missing the starting point where platform gets read in today.

@felixfontein
Copy link
Collaborator

@felixfontein
Copy link
Collaborator

I did look into this a bit more. To obtain the full platform information for a container, you need to look at the image the container uses. If I start a container with linux/amd64, the container just says "Platform": "linux", but the image says "Architecture": "amd64", "Os": "linux". This is using the OCI platform specification (https://github.com/containerd/containerd/blob/main/platforms/platforms.go#L52-L56).

The platform string uses the format defined here: https://github.com/containerd/containerd/blob/main/platforms/platforms.go#L69

Matching that one to the OCI platform specification is most easily done with the Go package https://github.com/containerd/containerd/blob/main/platforms/platforms.go, which we cannot use in Python code. So we'd have to re-implement this matching. The main problem (in sense of amount of work) are normalizations (https://github.com/containerd/containerd/blob/main/platforms/platforms.go#L80-L96).

I guess not doing normalizations, but forcing users to do the normalization by themselves, would already be a good start though.

@felixfontein
Copy link
Collaborator

I've implemented this in #705, and it seems to work. Would be great if some more folks could try this out :)

@felixfontein
Copy link
Collaborator

This is now released in 3.5.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working docker-plain plain Docker (no swarm, no compose, no stack)
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants