简体   繁体   English

如何从 docker 容器访问主机端口

[英]How to access host port from docker container

I have a docker container running jenkins.我有一个运行 jenkins 的 docker 容器。 As part of the build process, I need to access a web server that is run locally on the host machine.作为构建过程的一部分,我需要访问在主机上本地运行的 Web 服务器。 Is there a way the host web server (which can be configured to run on a port) can be exposed to the jenkins container?有没有办法可以将主机 Web 服务器(可以配置为在端口上运行)暴露给 jenkins 容器?

EDIT: I'm running docker natively on a Linux machine.编辑:我在 Linux 机器上本地运行 docker。

UPDATE:更新:

In addition to @larsks answer below, to get the IP address of the Host IP from the host machine, I do the following:除了下面的@larsks 回答,要从主机获取主机 IP 的 IP 地址,我执行以下操作:

ip addr show docker0 | grep -Po 'inet \K[\d.]+'

For all platforms适用于所有平台

Docker v 20.10 and above (since December 14th 2020) Docker v 20.10 及更高版本(自 2020 年 12 月 14 日起)

On Linux, add --add-host=host.docker.internal:host-gateway to your Docker command to enable this feature.在 Linux 上,将--add-host=host.docker.internal:host-gateway到 Docker 命令以启用此功能。 (See below for Docker Compose configuration.) (有关 Docker Compose 配置,请参见下文。)

Use your internal IP address or connect to the special DNS name host.docker.internal which will resolve to the internal IP address used by the host.使用您的内部 IP 地址或连接到特殊的 DNS 名称host.docker.internal ,它将解析为主机使用的内部 IP 地址。

To enable this in Docker Compose on Linux, add the following lines to the container definition:要在 Linux 上的 Docker Compose 中启用此功能,请将以下几行添加到容器定义中:

 extra_hosts: - "host.docker.internal:host-gateway"

For macOS and Windows对于 macOS 和 Windows

Docker v 18.03 and above (since March 21st 2018) Docker v 18.03 及更高版本(自 2018 年 3 月 21 日起)

Use your internal IP address or connect to the special DNS name host.docker.internal which will resolve to the internal IP address used by the host.使用您的内部 IP 地址或连接到特殊的 DNS 名称host.docker.internal ,它将解析为主机使用的内部 IP 地址。

Linux support pending https://github.com/docker/for-linux/issues/264 Linux 支持待定https://github.com/docker/for-linux/issues/264

MacOS with earlier versions of Docker带有早期 Docker 版本的 MacOS

Docker for Mac v 17.12 to v 18.02 Docker for Mac v 17.12 到 v 18.02

Same as above but use docker.for.mac.host.internal instead.同上,但使用docker.for.mac.host.internal代替。

Docker for Mac v 17.06 to v 17.11 Docker for Mac v 17.06 到 v 17.11

Same as above but use docker.for.mac.localhost instead.同上,但使用docker.for.mac.localhost代替。

Docker for Mac 17.05 and below Docker for Mac 17.05 及以下

To access host machine from the docker container you must attach an IP alias to your network interface.要从 docker 容器访问主机,您必须将 IP 别名附加到您的网络接口。 You can bind whichever IP you want, just make sure you're not using it to anything else.你可以绑定任何你想要的 IP,只要确保你没有将它用于其他任何东西。

sudo ifconfig lo0 alias 123.123.123.123/24

Then make sure that you server is listening to the IP mentioned above or 0.0.0.0 .然后确保您的服务器正在侦听上面提到的 IP 或0.0.0.0 If it's listening on localhost 127.0.0.1 it will not accept the connection.如果它正在侦听 localhost 127.0.0.1 ,它将不接受连接。

Then just point your docker container to this IP and you can access the host machine!然后只需将您的 docker 容器指向这个 IP,您就可以访问主机了!

To test you can run something like curl -X GET 123.123.123.123:3000 inside the container.要进行测试,您可以在容器内运行curl -X GET 123.123.123.123:3000之类的内容。

The alias will reset on every reboot so create a start-up script if necessary.别名将在每次重新启动时重置,因此如有必要,请创建启动脚本。

Solution and more documentation here: https://docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds此处的解决方案和更多文档: https : //docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds

When running Docker natively on Linux, you can access host services using the IP address of the docker0 interface.在 Linux 上本地运行 Docker 时,您可以使用docker0接口的 IP 地址访问主机服务。 From inside the container, this will be your default route.从容器内部,这将是您的默认路由。

For example, on my system:例如,在我的系统上:

$ ip addr show docker0
7: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::f4d2:49ff:fedd:28a0/64 scope link 
       valid_lft forever preferred_lft forever

And inside a container:在容器内:

# ip route show
default via 172.17.0.1 dev eth0 
172.17.0.0/16 dev eth0  src 172.17.0.4 

It's fairly easy to extract this IP address using a simple shell script:使用简单的 shell 脚本提取这个 IP 地址相当容易:

#!/bin/sh

hostip=$(ip route show | awk '/default/ {print $3}')
echo $hostip

You may need to modify the iptables rules on your host to permit connections from Docker containers.您可能需要修改主机上的iptables规则以允许来自 Docker 容器的连接。 Something like this will do the trick:像这样的事情可以解决问题:

# iptables -A INPUT -i docker0 -j ACCEPT

This would permit access to any ports on the host from Docker containers.这将允许从 Docker 容器访问主机上的任何端口。 Note that:注意:

  • iptables rules are ordered, and this rule may or may not do the right thing depending on what other rules come before it. iptables 规则是有序的,这个规则可能会或可能不会做正确的事情,这取决于它之前的其他规则。

  • you will only be able to access host services that are either (a) listening on INADDR_ANY (aka 0.0.0.0) or that are explicitly listening on the docker0 interface.您将只能访问 (a) 侦听INADDR_ANY (又名 0.0.0.0)或显式侦听docker0接口的主机服务。


If you are using Docker on MacOS or Windows 18.03+, you can connect to the magic hostname host.docker.internal .如果您在MacOSWindows 18.03+ 上使用 Docker,则可以连接到魔术主机名host.docker.internal


Lastly, under Linux you can run your container in the host network namespace by setting --net=host ;最后,在 Linux 下,您可以通过设置--net=host在主机网络命名空间中运行您的容器; in this case localhost on your host is the same as localhost inside the container, so containerized service will act like non-containerized services and will be accessible without any additional configuration.在这种情况下, localhost上的localhost与容器内的localhost相同,因此容器化服务将像非容器化服务一样运行,无需任何额外配置即可访问。

在您的--net="host" docker run命令中使用--net="host" ,然后您的 docker 容器中的localhost将指向您的 docker 主机。

For linux systems, you can – starting from major version 20.04 of the docker engine – now also communicate with the host via host.docker.internal .对于 linux 系统,从host.docker.internal引擎的主要版本20.04开始,您现在还可以通过host.docker.internal与主机通信。 This won't work automatically , but you need to provide the following run flag:这不会自动工作,但您需要提供以下运行标志:

--add-host=host.docker.internal:host-gateway

See

Solution with docker-compose: For accessing to host-based service, you can use network_mode parameter https://docs.docker.com/compose/compose-file/#network_mode docker-compose 解决方案:访问基于主机的服务,可以使用network_mode参数https://docs.docker.com/compose/compose-file/#network_mode

version: '3'
services:
  jenkins:
    network_mode: host

EDIT 2020-04-27: recommended for use only in local development environment.编辑 2020-04-27:建议仅在本地开发环境中使用。

EDIT 2021-09-21: IHaveHandedInMyResignation wrote it does not work for Mac and Windows.编辑 2021-09-21:IHaveHandedInMyResignation 写道它不适用于 Mac 和 Windows。 Option is supported only for Linux选项仅支持 Linux

I created a docker container for doing exactly that https://github.com/qoomon/docker-host我创建了一个 docker 容器来做这个https://github.com/qoomon/docker-host

You can then simply use container name dns to access host system eg curl http://dockerhost:9200然后您可以简单地使用容器名称 dns 来访问主机系统,例如curl http://dockerhost:9200

Currently the easiest way to do this on Mac and Windows is using host host.docker.internal , that resolves to host machine's IP address.目前在 Mac 和 Windows 上执行此操作的最简单方法是使用主机host.docker.internal ,它解析为主机的 IP 地址。 Unfortunately it does not work on linux yet (as of April 2018).不幸的是,它还不适用于 linux (截至 2018 年 4 月)。

I've explored the various solution and I find this the least hacky solution:我探索了各种解决方案,我发现这是最简单的解决方案:

  1. Define a static IP address for the bridge gateway IP.为网桥网关 IP 定义一个静态 IP 地址。
  2. Add the gateway IP as an extra entry in the extra_hosts directive.extra_hosts指令中添加网关 IP 作为额外条目。

The only downside is if you have multiple networks or projects doing this, you have to ensure that their IP address range do not conflict.唯一的缺点是如果您有多个网络或项目这样做,您必须确保它们的 IP 地址范围不冲突。

Here is a Docker Compose example:这是一个 Docker Compose 示例:

version: '2.3'

services:
  redis:
    image: "redis"
    extra_hosts:
      - "dockerhost:172.20.0.1"

networks:
  default:
    ipam:
      driver: default
      config:
      - subnet: 172.20.0.0/16
        gateway: 172.20.0.1

You can then access ports on the host from inside the container using the hostname "dockerhost".然后,您可以使用主机名“dockerhost”从容器内部访问主机上的端口。

We found that a simpler solution to all this networking junk is to just use the domain socket for the service.我们发现解决所有这些网络垃圾的一个更简单的解决方案是只使用域套接字来提供服务。 If you're trying to connect to the host anyway, just mount the socket as a volume, and you're on your way.如果您无论如何都尝试连接到主机,只需将套接字安装为卷,就可以了。 For postgresql, this was as simple as:对于 postgresql,这很简单:

docker run -v /var/run/postgresql:/var/run/postgresql

Then we just set up our database connection to use the socket instead of network.然后我们只需设置我们的数据库连接以使用套接字而不是网络。 Literally that easy.字面意思就是这么简单。

My google search brought me to here, and after digging in the comments I found it's a duplicate of From inside of a Docker container, how do I connect to the localhost of the machine?我的谷歌搜索将我带到这里,在挖掘评论后,我发现它是From inside of a Docker container, how do I connect to the localhost of the machine? . . I voted for closing this one as a duplicate, but since people (including myself!) often scroll down on the answers rather than reading the comments carefully, here is a short answer.我投票赞成关闭这个重复,但由于人们(包括我自己!)经常向下滚动答案而不是仔细阅读评论,这里是一个简短的答案。

TL;DR:特尔;博士:

Replace http://127.0.0.1 or http://localhost with http://host.docker.internal .http://127.0.0.1http://localhost替换为http://host.docker.internal ( Source ) 来源

For docker-compose using bridge networking to create a private network between containers, the accepted solution using docker0 doesn't work because the egress interface from the containers is not docker0 , but instead, it's a randomly generated interface id, such as:对于使用桥接网络在容器之间创建专用网络的docker0 docker-compose ,使用docker0的公认解决方案不起作用,因为来自容器的出口接口不是docker0 ,而是随机生成的接口 id,例如:

$ ifconfig

br-02d7f5ba5a51: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.32.1  netmask 255.255.240.0  broadcast 192.168.47.255

Unfortunately that random id is not predictable and will change each time compose has to recreate the network (eg on a host reboot).不幸的是,随机 id 是不可预测的,并且每次 compose 必须重新创建网络时都会更改(例如,在主机重新启动时)。 My solution to this is to create the private network in a known subnet and configure iptables to accept that range:我对此的解决方案是在已知子网中创建专用网络并配置iptables以接受该范围:

Compose file snippet:编写文件片段:

version: "3.7"

services:
  mongodb:
    image: mongo:4.2.2
    networks:
    - mynet
    # rest of service config and other services removed for clarity

networks:
  mynet:
    name: mynet
    ipam:
      driver: default
      config:
      - subnet: "192.168.32.0/20"

You can change the subnet if your environment requires it.如果您的环境需要,您可以更改子网。 I arbitrarily selected 192.168.32.0/20 by using docker network inspect to see what was being created by default.我通过使用docker network inspect任意选择192.168.32.0/20来查看默认创建的内容。

Configure iptables on the host to permit the private subnet as a source:在主机上配置iptables以允许私有子网作为源:

$ iptables -I INPUT 1 -s 192.168.32.0/20 -j ACCEPT

This is the simplest possible iptables rule.这是最简单的iptables规则。 You may wish to add other restrictions, for example by destination port.您可能希望添加其他限制,例如通过目标端口。 Don't forget to persist your iptables rules when you're happy they're working.当您对 iptables 的工作感到满意时,不要忘记坚持您的 iptables 规则。

This approach has the advantage of being repeatable and therefore automatable.这种方法的优点是可重复,因此可自动化。 I use ansible's template module to deploy my compose file with variable substitution and then use the iptables and shell modules to configure and persist the firewall rules, respectively.我使用 ansible 的template模块通过变量替换部署我的撰写文件,然后使用iptablesshell模块分别配置和保留防火墙规则。

This is an old question and had many answers, but none of those fit well enough to my context.这是一个古老的问题,有很多答案,但没有一个适合我的上下文。 In my case, the containers are very lean and do not contain any of the networking tools necessary to extract the host's ip address from within the container.就我而言,容器非常精简,不包含从容器内提取主机 IP 地址所需的任何网络工具。

Also, usin the --net="host" approach is a very rough approach that is not applicable when one wants to have well isolated network configuration with several containers.此外,使用--net="host"方法是一种非常粗略的方法,当您想要具有多个容器的良好隔离的网络配置时不适用。

So, my approach is to extract the hosts' address at the host's side, and then pass it to the container with --add-host parameter:所以,我的方法是在主机端提取主机地址,然后使用--add-host参数将其传递给容器:

$ docker run --add-host=docker-host:`ip addr show docker0 | grep -Po 'inet \K[\d.]+'` image_name

or, save the host's IP address in an environment variable and use the variable later:或者,将主机的 IP 地址保存在环境变量中并稍后使用该变量:

$ DOCKERIP=`ip addr show docker0 | grep -Po 'inet \K[\d.]+'`
$ docker run --add-host=docker-host:$DOCKERIP image_name

And then the docker-host is added to the container's hosts file, and you can use it in your database connection strings or API URLs.然后将docker-host添加到容器的主机文件中,您可以在数据库连接字符串或 API URL 中使用它。

You can access the local webserver which is running in your host machine in two ways.您可以通过两种方式访问​​在您的主机上运行的本地网络服务器。

  1. Approach 1 with public IP使用公共 IP 的方法 1

    Use host machine public IP address to access webserver in Jenkins docker container.使用主机公共 IP 地址访问 Jenkins docker 容器中的 web 服务器。

  2. Approach 2 with the host network方法二与主机网络

    Use "--net host" to add the Jenkins docker container on the host's network stack.使用“--net host”在主机的网络堆栈上添加 Jenkins docker 容器。 Containers which are deployed on host's stack have entire access to the host interface.部署在主机堆栈上的容器可以完全访问主机接口。 You can access local webserver in docker container with a private IP address of the host machine.您可以使用主机的私有 IP 地址访问 docker 容器中的本地 Web 服务器。

NETWORK ID          NAME                      DRIVER              SCOPE
b3554ea51ca3        bridge                    bridge              local
2f0d6d6fdd88        host                      host                local
b9c2a4bc23b2        none                      null                local

Start a container with the host network Eg: docker run --net host -it ubuntu and run ifconfig to list all available network IP addresses which are reachable from docker container.使用主机网络启动一个容器, Eg: docker run --net host -it ubuntu并运行ifconfig以列出可从 docker 容器访问的所有可用网络 IP 地址。

Eg: I started a nginx server in my local host machine and I am able to access the nginx website URLs from Ubuntu docker container.例如:我在本地主机上启动了一个 nginx 服务器,我可以从 Ubuntu docker 容器访问 nginx 网站 URL。

docker run --net host -it ubuntu

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
a604f7af5e36        ubuntu              "/bin/bash"         22 seconds ago      Up 20 seconds                           ubuntu_server

Accessing the Nginx web server (running in local host machine) from Ubuntu docker container with private network IP address.从具有私有网络 IP 地址的 Ubuntu docker 容器访问 Nginx Web 服务器(在本地主机中运行)。

root@linuxkit-025000000001:/# curl 192.168.x.x -I
HTTP/1.1 200 OK
Server: nginx/1.15.10
Date: Tue, 09 Apr 2019 05:12:12 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 26 Mar 2019 14:04:38 GMT
Connection: keep-alive
ETag: "5c9a3176-264"
Accept-Ranges: bytes

For me (Windows 10, Docker Engine v19.03.8) it was a mix of https://stackoverflow.com/a/43541732/7924573 and https://stackoverflow.com/a/50866007/7924573 .对我来说(Windows 10,Docker Engine v19.03.8)它是https://stackoverflow.com/a/43541732/7924573https://stackoverflow.com/a/50866007/7924573的混合。

  1. change the host/ip to host.docker.internal将主机/IP 更改为host.docker.internal
    eg: LOGGER_URL = " http://host.docker.internal:8085/log "例如:LOGGER_URL = " http://host.docker.internal:8085/log "
  2. set the network_mode to bridge (if you want to maintain the port forwarding; if not use host ):将 network_mode 设置为桥接(如果要维护端口转发;如果不使用host ):
    version: '3.7' services: server: build: . ports: - "5000:5000" network_mode: bridge version: '3.7' services: server: build: . ports: - "5000:5000" network_mode: bridge or alternatively: Use --net="bridge" if you are not using docker-compose (similar to https://stackoverflow.com/a/48806927/7924573 ) version: '3.7' services: server: build: . ports: - "5000:5000" network_mode: bridge或者:如果您不使用 docker-compose,请使用--net="bridge" (类似于https://stackoverflow.com/a/48806927/7924573
    As pointed out in previous answers: This should only be used in a local development environment .正如之前的答案所指出的:这应该只在本地开发环境中使用
    For more information read: https://docs.docker.com/compose/compose-file/#network_mode and https://docs.docker.com/docker-for-windows/networking/#use-cases-and-workarounds有关更多信息,请阅读: https : //docs.docker.com/compose/compose-file/#network_modehttps://docs.docker.com/docker-for-windows/networking/#use-cases-and-workarounds

The simplest option that worked for me was, I used the IP address of my machine on the local network(assigned by the router)对我有用的最简单的选项是,我在本地网络上使用了我机器的 IP 地址(由路由器分配)

You can find this using the ifconfig command您可以使用ifconfig命令找到它

eg例如

ifconfig

en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        options=400<CHANNEL_IO>
        ether f0:18:98:08:74:d4 
        inet 192.168.178.63 netmask 0xffffff00 broadcast 192.168.178.255
        media: autoselect
        status: active

and then used the inet address.然后使用 inet 地址。 This worked for me to connect any ports on my machine.这对我来说可以连接我机器上的任何端口。

TLDR for Mac and Windows 适用于Mac和Windows的TLDR

docker run -it --rm alpine nslookup host.docker.internal

... prints the host's IP address ... ...打印主机的IP地址...

nslookup: can't resolve '(null)': Name does not resolve

Name:      host.docker.internal
Address 1: 192.168.65.2

Details 细节

On Mac and Windows , you can use the special DNS name host.docker.internal . MacWindows上 ,可以使用特殊的DNS名称host.docker.internal

The host has a changing IP address (or none if you have no network access). 主机的IP地址正在更改(如果没有网络访问权限,则没有IP地址)。 From 18.03 onwards our recommendation is to connect to the special DNS name host.docker.internal, which resolves to the internal IP address used by the host. 从18.03开始,我们的建议是连接到特殊的DNS名称host.docker.internal,它将解析为主机使用的内部IP地址。 This is for development purpose and will not work in a production environment outside of Docker Desktop for Mac. 这是出于开发目的,不适用于Docker Desktop for Mac以外的生产环境。

In almost 7 years the question was asked, it is either docker has changed, or no one tried this way.在将近 7 年的时间里,有人问了这个问题,要么是 docker 改变了,要么没有人尝试过这种方式。 So I will include my own answer.所以我将包括我自己的答案。

I have found all answers use complex methods.我发现所有答案都使用复杂的方法。 Today, I have needed this, and found 2 very simple ways:今天,我需要这个,并找到了2个非常简单的方法:

  • use ipconfig or ifconfig on your host and make note of all IP addresses.在您的主机上使用ipconfigifconfig并记下所有 IP 地址。 At least two of them can be used by the container.容器至少可以使用其中的两个。

    • I have a fixed local network address on WiFi LAN Adapter: 192.168.1.101 .我在 WiFi LAN 适配器上有一个固定的本地网络地址: 192.168.1.101 This could be 10.0.1.101 .这可能是10.0.1.101 the result will change depending on your router结果将根据您的路由器而改变
    • I use WSL on windows, and it has its own vEthernet address: 172.19.192.1我在 Windows 上使用 WSL,它有自己的vEthernet地址: 172.19.192.1
  • use host.docker.internal .使用host.docker.internal Most answers have this or another form of it depending on OS.大多数答案都有这种或另一种形式,具体取决于操作系统。 The name suggests it is now globally used by docker.顾名思义,它现在被 docker 全局使用。

A third option is to use WAN address of the machine, or in other words IP given by the service provider.第三种选择是使用机器的 WAN 地址,或者换句话说,由服务提供商提供的 IP。 However, this may not work if IP is not static, and requires routing and firewall settings.但是,如果 IP 不是静态的,并且需要路由和防火墙设置,这可能不起作用。


PS: Although pretty identical to this question here , and I posted this answer there, I first found this post, so I post it here too as may forget my own answer. PS:虽然和这里的这个问题非常相似,并且我在那里发布了这个答案,但我首先找到了这篇文章,所以我也将它发布在这里,因为可能会忘记我自己的答案。

When you have two docker images "already" created and you want to put two containers to communicate with one-another.当您“已经”创建了两个 docker 镜像并且您想要放置两个容器以相互通信时。

For that, you can conveniently run each container with its own --name and use the --link flag to enable communication between them.为此,您可以使用自己的 --name 方便地运行每个容器,并使用 --link 标志启用它们之间的通信。 You do not get this during docker build though.但是,在 docker build 期间您不会得到这个。

When you are in a scenario like myself, and it is your当你在像我这样的场景中,这是你的

docker build -t "centos7/someApp" someApp/ 

That breaks when you try to当您尝试这样做时,这会中断

curl http://172.17.0.1:localPort/fileIWouldLikeToDownload.tar.gz > dump.tar.gz

and you get stuck on "curl/wget" returning no "route to host".并且你被困在“curl/wget”上,没有返回“到主机的路由”。

The reason is security that is set in place by docker that by default is banning communication from a container towards the host or other containers running on your host.原因是 docker 设置的安全性,默认情况下禁止从容器到主机或主机上运行的其他容器的通信。 This was quite surprising to me, I must say, you would expect the echosystem of docker machines running on a local machine just flawlessly can access each other without too much hurdle.这让我很惊讶,我必须说,你会期望在本地机器上运行的 docker 机器的回声系统可以完美地相互访问而没有太多障碍。

The explanation for this is described in detail in the following documentation.对此的解释在以下文档中有详细描述。

http://www.dedoimedo.com/computers/docker-networking.html http://www.dedoimedo.com/computers/docker-networking.html

Two quick workarounds are given that help you get moving by lowering down the network security.提供了两种快速解决方法,可通过降低网络安全性来帮助您继续前进。

The simplest alternative is just to turn the firewall off - or allow all.最简单的替代方法是关闭防火墙 - 或允许所有。 This means running the necessary command, which could be systemctl stop firewalld, iptables -F or equivalent.这意味着运行必要的命令,可以是 systemctl stop firewalld、iptables -F 或等效命令。

Hope this information helps you.希望这些信息对您有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM