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

Change default process type host to IPv6 :: #354

Merged
merged 4 commits into from
Nov 27, 2024

Conversation

schneems
Copy link
Contributor

IPv6 is the future. Here's some more context heroku/roadmap#40.

Related heroku/ruby-getting-started#165

@schneems
Copy link
Contributor Author

Failing with:

thread 'test_default_app_latest_distro' panicked at buildpacks/ruby/tests/integration_test.rs:106:84:
called `Result::unwrap()` on an `Err` value: Transport(Transport { kind: Io, message: None, url: Some(Url { scheme: "http", cannot_be_a_base: false, username: "", password: None, host: Some(Ipv4(127.0.0.1)), port: Some(65188), path: "/", query: None, fragment: None }), source: Some(Custom { kind: ConnectionAborted, error: "Unexpected EOF" }) })
stack backtrace:
   0: rust_begin_unwind
             at /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14/library/std/src/panicking.rs:662:5
   1: core::panicking::panic_fmt
             at /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14/library/core/src/panicking.rs:74:14
   2: core::result::unwrap_failed
             at /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14/library/core/src/result.rs:1677:5
   3: core::result::Result<T,E>::unwrap
             at /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14/library/core/src/result.rs:1102:23
   4: integration_test::test_default_app_latest_distro::{{closure}}::{{closure}}::{{closure}}
             at ./tests/integration_test.rs:106:40
   5: libcnb_test::test_context::TestContext::start_container
             at /Users/rschneeman/.cargo/registry/src/index.crates.io-6f17d22bba15001f/libcnb-test-0.25.0/src/test_context.rs:129:9
   6: integration_test::test_default_app_latest_distro::{{closure}}::{{closure}}
             at ./tests/integration_test.rs:101:17
   7: libcnb_test::test_runner::TestRunner::build_internal
             at /Users/rschneeman/.cargo/registry/src/index.crates.io-6f17d22bba15001f/libcnb-test-0.25.0/src/test_runner.rs:175:9
   8: libcnb_test::test_context::TestContext::rebuild
             at /Users/rschneeman/.cargo/registry/src/index.crates.io-6f17d22bba15001f/libcnb-test-0.25.0/src/test_context.rs:285:9
   9: integration_test::test_default_app_latest_distro::{{closure}}
             at ./tests/integration_test.rs:97:13
  10: libcnb_test::test_runner::TestRunner::build_internal
             at /Users/rschneeman/.cargo/registry/src/index.crates.io-6f17d22bba15001f/libcnb-test-0.25.0/src/test_runner.rs:175:9
  11: libcnb_test::test_runner::TestRunner::build
             at /Users/rschneeman/.cargo/registry/src/index.crates.io-6f17d22bba15001f/libcnb-test-0.25.0/src/test_runner.rs:59:9
  12: integration_test::test_default_app_latest_distro
             at ./tests/integration_test.rs:85:5
  13: integration_test::test_default_app_latest_distro::{{closure}}
             at ./tests/integration_test.rs:82:36
  14: core::ops::function::FnOnce::call_once
             at /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14/library/core/src/ops/function.rs:250:5
  15: core::ops::function::FnOnce::call_once
             at /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

The host: Some(Ipv4(127.0.0.1)) stands out as maybe a problem.

@edmorley
Copy link
Member

The host: Some(Ipv4(127.0.0.1)) stands out as maybe a problem.

I think that's expected from the test runner - since the connection from the integration tests to the container will be IPv4.

Does using [::] instead of :: as the address fix the error?

For gunicorn I had to use [::] since it was being parsed as a URL, and on https://en.wikipedia.org/wiki/IPv6#Address_representation it says:

Because IPv6 addresses contain colons, and URLs use colons to separate the host from the port number, an IPv6 address used as the host-part of a URL should be enclosed in square brackets

@schneems
Copy link
Contributor Author

Good call. Looks like support might vary by webserver puma/puma#1356 (comment).

With [::] using webrick and rackup I get:

thread 'test_default_app_latest_distro' panicked at /Users/rschneeman/.cargo/registry/src/index.crates.io-6f17d22bba15001f/libcnb-test-0.25.0/src/container_context.rs:130:17:
Error obtaining container port mapping:
Error: No public port '1234' published for libcnbtest_pddfipppqvub

This normally means that the container crashed. Container logs:

## stderr:

[2024-11-25 02:12:47] INFO  WEBrick 1.7.0
[2024-11-25 02:12:47] INFO  ruby 3.1.3 (2022-11-24) [aarch64-linux]
bundler: failed to load command: rackup (/layers/heroku_ruby/gems/ruby/3.1.0/bin/rackup)
/layers/heroku_ruby/ruby/lib/ruby/3.1.0/socket.rb:227:in `getaddrinfo': getaddrinfo: Name or service not known (SocketError)
	from /layers/heroku_ruby/ruby/lib/ruby/3.1.0/socket.rb:227:in `foreach'
	from /layers/heroku_ruby/ruby/lib/ruby/3.1.0/socket.rb:763:in `tcp_server_sockets'
	from /layers/heroku_ruby/gems/ruby/3.1.0/gems/webrick-1.7.0/lib/webrick/utils.rb:60:in `create_listeners'
	from /layers/heroku_ruby/gems/ruby/3.1.0/gems/webrick-1.7.0/lib/webrick/server.rb:130:in `listen'
	from /layers/heroku_ruby/gems/ruby/3.1.0/gems/webrick-1.7.0/lib/webrick/server.rb:111:in `initialize'
	from /layers/heroku_ruby/gems/ruby/3.1.0/gems/webrick-1.7.0/lib/webrick/httpserver.rb:47:in `initialize'
	from /layers/heroku_ruby/gems/ruby/3.1.0/gems/rack-2.2.3/lib/rack/handler/webrick.rb:38:in `new'
	from /layers/heroku_ruby/gems/ruby/3.1.0/gems/rack-2.2.3/lib/rack/handler/webrick.rb:38:in `run'
	from /layers/heroku_ruby/gems/ruby/3.1.0/gems/rack-2.2.3/lib/rack/server.rb:327:in `start'
	from /layers/heroku_ruby/gems/ruby/3.1.0/gems/rack-2.2.3/lib/rack/server.rb:168:in `start'
	from /layers/heroku_ruby/gems/ruby/3.1.0/gems/rack-2.2.3/bin/rackup:5:in `<top (required)>'

With :: with webrick and rackup I get the original error (above):

[2024-11-25 02:18:45] INFO  WEBrick 1.7.0
[2024-11-25 02:18:45] INFO  ruby 3.1.3 (2022-11-24) [aarch64-linux]
[2024-11-25 02:18:45] INFO  WEBrick::HTTPServer#start: pid=1 port=1234

thread 'test_default_app_latest_distro' panicked at buildpacks/ruby/tests/integration_test.rs:106:84:
called `Result::unwrap()` on an `Err` value: Transport(Transport { kind: Io, message: None, url: Some(Url { scheme: "http", cannot_be_a_base: false, username: "", password: None, host: Some(Ipv4(127.0.0.1)), port: Some(51377), path: "/", query: None, fragment: None }), source: Some(Custom { kind: ConnectionAborted, error: "Unexpected EOF" }) })
stack backtrace:
   0: rust_begin_unwind
             at /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14/library/std/src/panicking.rs:662:5
   1: core::panicking::panic_fmt
             at /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14/library/core/src/panicking.rs:74:14
   2: core::result::unwrap_failed
             at /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14/library/core/src/result.rs:1677:5
   3: core::result::Result<T,E>::unwrap
             at /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14/library/core/src/result.rs:1102:23

I tried patching libcnb-test to return an IPv6 connection heroku/libcnb.rs#884, but I still get the same EOF error, but now it's an IPv6 address :

thread 'test_default_app_latest_distro' panicked at buildpacks/ruby/tests/integration_test.rs:106:84:
called `Result::unwrap()` on an `Err` value: Transport(Transport { kind: Io, message: None, url: Some(Url { scheme: "http", cannot_be_a_base: false, username: "", password: None, host: Some(Ipv6(::1)), port: Some(51712), path: "/", query: None, fragment: None }), source: Some(Custom { kind: ConnectionAborted, error: "Unexpected EOF" }) })
stack backtrace:
   0: rust_begin_unwind
             at /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14/library/std/src/panicking.rs:662:5
   1: core::panicking::panic_fmt

@schneems
Copy link
Contributor Author

Short

I think I can make this work by switching the default app to use puma instead of webrick. However the implication is also that webrick cannot work with both IPv4 and IPv6 (it looks like a bug/problem in webrick) unless there's more information.

Long

I'm not 100% confident in this statement. But I'm leaning towards: Webrick supports IPv6 OR IPv4 but not both at the same time. While Rails w/ Puma can support both. Here's why I'm saying that:

I booted Rails in a variety of configurations to see how it will look to netstat -an here's the conclusion https://gist.github.com/schneems/ffc51f61e6ee213b29e676c89e0579d0.

When something is correctly bound to :: then I expect to see:

$ netstat -an | grep 'LISTEN' 
tcp46      0      0  *.3000                 *.*                    LISTEN

Specifically tcp46.

When I boot with a host of :: I get:

$ bundle exec rackup --host "::"
[2024-11-25 16:43:27] INFO  WEBrick 1.9.0
[2024-11-25 16:43:27] INFO  ruby 3.3.1 (2024-04-23) [arm64-darwin23]
[2024-11-25 16:43:27] INFO  WEBrick::HTTPServer#start: pid=48714 port=9292
$ netstat -an | grep 'LISTEN' | grep 9292
tcp6       0      0  *.9292                 *.*                    LISTEN

Webrick only binding to tcp6 and not tcp4. i.e. not tcp46 versus swapping in puma:

$ bundle exec rackup --host "::"
Puma starting in single mode...
* Puma version: 6.5.0 ("Sky's Version")
* Ruby version: ruby 3.3.1 (2024-04-23 revision c56cd86388) [arm64-darwin23]
*  Min threads: 0
*  Max threads: 5
*  Environment: development
*          PID: 54099
* Listening on http://[::]:9292
Use Ctrl-C to stop

I get both binds:

$ netstat -an | grep 'LISTEN' | grep 9292
tcp46      0      0  *.9292                 *.*                    LISTEN

I think that this will work with webrick in an environment where IPv6 is being used, but it won't support both IPv4 and IPv6 at the same time. It's an either/or scenario. My guess is that the tests are failing due to using IPv4 for requests in the test/docker environment. I'm going to try to switch it to using puma, but that basically means it won't work with webrick.

@schneems schneems marked this pull request as ready for review November 25, 2024 23:02
@schneems schneems requested a review from a team as a code owner November 25, 2024 23:02
@edmorley
Copy link
Member

However the implication is also that webrick cannot work with both IPv4 and IPv6 (it looks like a bug/problem in webrick) unless there's more information.

This seems related:
ruby/webrick#99

@schneems schneems merged commit 03f8456 into main Nov 27, 2024
6 checks passed
@schneems schneems deleted the schneems/ipv6-host-default branch November 27, 2024 15:49
heroku-linguist bot added a commit that referenced this pull request Nov 27, 2024
## heroku/ruby

### Changed

- Default process types defined by the Ruby buildpack now use IPv6 host `::` which is equivalent of IPv4 host `0.0.0.0`. This will only affect applications that do not define a `web` process type via the `Procfile` and [Procfile Cloud Native Buildpack](https://github.com/heroku/buildpacks-procfile). Those applications must make sure to update their configuration to bind to an IPv6 host. ([#354](#354))

### Added

- The buildpack now warns the user when environmental variables used in running the default process are not defined. ([#307](#307))
@heroku-linguist heroku-linguist bot mentioned this pull request Nov 27, 2024
heroku-linguist bot added a commit that referenced this pull request Nov 27, 2024
## heroku/ruby

### Changed

- Default process types defined by the Ruby buildpack now use IPv6 host `::` which is equivalent of IPv4 host `0.0.0.0`. This will only affect applications that do not define a `web` process type via the `Procfile` and [Procfile Cloud Native Buildpack](https://github.com/heroku/buildpacks-procfile). Those applications must make sure to update their configuration to bind to an IPv6 host. ([#354](#354))

### Added

- The buildpack now warns the user when environmental variables used in running the default process are not defined. ([#307](#307))

Co-authored-by: heroku-linguist[bot] <136119646+heroku-linguist[bot]@users.noreply.github.com>
heroku-linguist bot added a commit to heroku/cnb-builder-images that referenced this pull request Nov 27, 2024
## heroku/ruby

### Changed

- Default process types defined by the Ruby buildpack now use IPv6 host `::` which is equivalent of IPv4 host `0.0.0.0`. This will only affect applications that do not define a `web` process type via the `Procfile` and [Procfile Cloud Native Buildpack](https://github.com/heroku/buildpacks-procfile). Those applications must make sure to update their configuration to bind to an IPv6 host. ([#354](heroku/buildpacks-ruby#354))

### Added

- The buildpack now warns the user when environmental variables used in running the default process are not defined. ([#307](heroku/buildpacks-ruby#307))
heroku-linguist bot added a commit to heroku/cnb-builder-images that referenced this pull request Dec 9, 2024
## heroku/ruby

### Changed

- Default process types defined by the Ruby buildpack now use IPv6 host `::` which is equivalent of IPv4 host `0.0.0.0`. This will only affect applications that do not define a `web` process type via the `Procfile` and [Procfile Cloud Native Buildpack](https://github.com/heroku/buildpacks-procfile). Those applications must make sure to update their configuration to bind to an IPv6 host. ([#354](heroku/buildpacks-ruby#354))

### Added

- The buildpack now warns the user when environmental variables used in running the default process are not defined. ([#307](heroku/buildpacks-ruby#307))

Co-authored-by: heroku-linguist[bot] <136119646+heroku-linguist[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants