docker-library / php

Docker Official Image packaging for PHP
https://php.net
MIT License
3.82k stars 2k forks source link

[BUG] 8.1.0RC1 alpine images have broken networking/gethostbyaddr behaviour #1201

Closed sbuerk closed 3 years ago

sbuerk commented 3 years ago

We wanted to add php 8.1.0RC1 to our testing chain to start early mitigate issues in our projec(s).

As we uses the alpine images as base (size etc) we added the 8.1.0RC1 one and detected weired behaviors. We narrowed it down and can reproduce it with a simple test script.

Background: We have tests resolving '::1' ipv6 and should resolved to "localhost" or at least something other then ::1. What was weired is, that id did not worked. We moved it to the start of phpunit, from where we stripped down the test-file.

But it is 8.1.0RC1 not per se, local install works and even the other (as far as tested) seems to work, only the alpine onces are broken

To make sure we do not intrude the issue through our Dockerfile which installs further packages, we tested it against the original images build/released from here:

Create "test-folder/test.php" with following code:

<?php
echo "CHECK ::1 hostname before/after version compare" . PHP_EOL;

// duplicationg this line bevore other code lines, would work until something
// like version_compare is used.
// EXPECTED: localhost
echo "#1 IPv6(::1): " . (string)gethostbyaddr('::1') . PHP_EOL;

// this line chanes the return in 8.1.0RC1-alpine - but why ?
// but even other codelines changed it
if (!version_compare(PHP_VERSION, PHP_VERSION, '=')) {}

// EXPECTED: localhost => alpine ::1, others localhost as expected
echo "#2 IPv6(::1): " . (string)gethostbyaddr('::1') . PHP_EOL;

Test commands with outputs (in folder where test.php was created): Note: not all, just some as cross checks

// not working
$ docker run -it --rm --name blub -v "$PWD":/myapp -w /myapp php:8.1.0RC1-alpine php test.php

CHECK ::1 hostname before/after version compare
#1 IPv6(::1): localhost
#2 IPv6(::1): ::1
// not working
$ docker run -it --rm --name blub -v "$PWD":/myapp -w /myapp php:8.1.0RC1-alpine3.13 php test.php

CHECK ::1 hostname before/after version compare
#1 IPv6(::1): localhost
#2 IPv6(::1): ::1
// not working
$ docker run -it --rm --name blub -v "$PWD":/myapp -w /myapp php:8.1.0RC1-alpine3.14 php test.php

CHECK ::1 hostname before/after version compare
#1 IPv6(::1): localhost
#2 IPv6(::1): ::1
// working
$ docker run -it --rm --name blub -v "$PWD":/myapp -w /myapp php:8.0-alpine php test.php

CHECK ::1 hostname before/after version compare
#1 IPv6(::1): localhost
#2 IPv6(::1): localhost
// working
$ docker run -it --rm --name blub -v "$PWD":/myapp -w /myapp php:8.0-alpine3.13 php test.php

CHECK ::1 hostname before/after version compare
#1 IPv6(::1): localhost
#2 IPv6(::1): localhost
// working
$ docker run -it --rm --name blub -v "$PWD":/myapp -w /myapp php:8.0-alpine3.13 php test.php

CHECK ::1 hostname before/after version compare
#1 IPv6(::1): localhost
#2 IPv6(::1): localhost
// working
$ docker run -it --rm --name blub -v "$PWD":/myapp -w /myapp php:8.1.0RC1-cli php test.php

CHECK ::1 hostname before/after version compare
#1 IPv6(::1): localhost
#2 IPv6(::1): localhost
// working
$ docker run -it --rm --name blub -v "$PWD":/myapp -w /myapp php:8.1.0RC1 php test.php

CHECK ::1 hostname before/after version compare
#1 IPv6(::1): localhost
#2 IPv6(::1): localhost
// working
$ docker run -it --rm --name blub -v "$PWD":/myapp -w /myapp php:8.1.0RC1-cli-buster php test.php

CHECK ::1 hostname before/after version compare
#1 IPv6(::1): localhost
#2 IPv6(::1): localhost
// working
$ docker run -it --rm --name blub -v "$PWD":/myapp -w /myapp php:8.1.0RC1-buster php test.php

CHECK ::1 hostname before/after version compare
#1 IPv6(::1): localhost
#2 IPv6(::1): localhost

Basicly for 8.0 the sambe base images are used for alpine, and I did not found (yet) a different betwenn the 8.1.0RC1 builds from 8.0 which would explain this.

Anyone a clue how to "stabalize" it ?

Note: Checked /etc/hosts in the container, it has the right entries.

Thanks for any hints, how we can fix it on our sides - or where this behavour comes from.

tianon commented 3 years ago

This is strange -- I know there used to be a lot of bugs around gethostbyaddr and Alpine's behavior, but I can't seem to find a good reference for the previous issues now that I need it. I don't see anything interesting in 8.1's changelog that would lead to this, either. :confused:

sbuerk commented 3 years ago

Only things I can found are for other languages, not regarding ::1 but DNS resolving at all - and consens is through google to switch do another base image :/

sbuerk commented 3 years ago

So, I downloaded this repository and stepped back all buildfiles for php8.1(cli), for alpine 3.13/3.14 and tested it with the test-script added above.

None of them worked correctly.

If I drop in the key, hash and checksum for 8.0 into the dockerfile for the 8.1 one, either alpine 3.13/3.14 it workes correctly.

So I would guess now that php8.1 relay on something alpine do not provide - or not correctly.

I even tried out all steps with a full apk upgrade as first step, not worked.

So I think it's not really an issue here. Either something in alpine itself or more obious some changes in php itself.

Would be sad if no alpine 8.1 image could be used ....

sbuerk commented 3 years ago

Create php bug report for now:

https://bugs.php.net/bug.php?id=81441

tianon commented 3 years ago

It looks like there are PHP 8.1 packages in Alpine's Edge distribution too that are probably worth trying to see if they suffer from the same issue (as additional useful input for your bug): https://pkgs.alpinelinux.org/package/edge/testing/x86_64/php81

In this case, I don't think there's anything we can change/fix in the image itself to correct this, so I'm going to close this in favor of https://bugs.php.net/bug.php?id=81441. :grimacing:

nikic commented 3 years ago

PHP 8.1 switched to using getnameinfo() instead of the deprecated gethostbyaddr() (https://github.com/php/php-src/blob/a22f9fc104fee7466ad715d4e024b7ef9ede4e4e/ext/standard/dns.c#L183). Not seeing anything obvious wrong with that code. Is there something special about getnameinfo() on musl?

nikic commented 3 years ago

Hm, possibly this is because we're not initializing sin_port? Looking at the getnameinfo() man page, that might be required.

Edit: While we probably should do that for proprieties sake, musl only accesses the port if serv is passed, which we don't: https://github.com/ifduyue/musl/blob/cfdfd5ea3ce14c6abf7fb22a531f3d99518b5a1b/src/network/getnameinfo.c#L188

sbuerk commented 2 years ago

Just to note - 8.1.0RC6 contains bugfix for this issue.