设备或资源在容器中从零开始和高山繁忙,但在ubuntu上没有



我编辑了这个问题,但我的问题表现在一个高山容器中。我现在在一个容器中从头开始遇到同样的问题。这是同一个问题,但范围缩小了一点。

正如标题所描述的,我在Ubuntu容器中有一个可执行文件,用于构建我的应用程序,但一旦我将其复制到Alpine容器中,我就会得到具有相同可执行文件的Device or resource busy,我对发生的事情有点困惑。

这是我的档案:

ARG UBUNTU_VERSION=20.04
FROM ubuntu:${UBUNTU_VERSION} as builder
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get -y install 
curl 
g++-10 
gcc-10 
ninja-build 
unzip 
zip 
make 
perl 
pkg-config 
git 
gdb
RUN mkdir /opt/vcpkg 
&& curl -L -s "https://github.com/microsoft/vcpkg/tarball/8ce7b41302728ff6fc8bd377f572c4cbe8c64c1d" | tar --strip-components=1 -xz -C /opt/vcpkg 
&& /opt/vcpkg/bootstrap-vcpkg.sh
RUN mkdir /opt/cmake && 
curl -s "https://cmake.org/files/v3.18/cmake-3.18.0-Linux-x86_64.tar.gz" | tar --strip-components=1 -xz -C /opt/cmake
RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 10 && 
update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 10
ENV PATH="/opt/cmake/bin:/opt/vcpkg:${PATH}"
RUN mkdir /build2
COPY src2 /source/src2
WORKDIR /build2
RUN cmake /source/src2 
-DCMAKE_BUILD_TYPE=Release 
-DCMAKE_GENERATOR=Ninja 
-DCMAKE_MAKE_PROGRAM=/usr/bin/ninja 
-DCMAKE_INSTALL_PREFIX=/install 
-DCMAKE_TOOLCHAIN_FILE=/opt/vcpkg/scripts/buildsystems/vcpkg.cmake 
RUN cmake --build . --target all
FROM scratch
COPY --from=builder /build2/http-beast-ssl /http-beast-ssl
COPY --from=builder /lib64/ld-linux-x86-64.so.2 /lib64/ld-linux-x86-64.so.2
COPY --from=builder /usr/lib/x86_64-linux-gnu/libdl.so.2 /usr/lib/x86_64-linux-gnu/libdl.so.2
COPY --from=builder /usr/lib/x86_64-linux-gnu/libpthread.so.0 /usr/lib/x86_64-linux-gnu/libpthread.so.0
COPY --from=builder /usr/lib/x86_64-linux-gnu/libstdc++.so.6 /usr/lib/x86_64-linux-gnu/libstdc++.so.6
COPY --from=builder /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28
COPY --from=builder /usr/lib/x86_64-linux-gnu/libgcc_s.so.1 /usr/lib/x86_64-linux-gnu/libgcc_s.so.1
COPY --from=builder /usr/lib/x86_64-linux-gnu/libc.so.6 /usr/lib/x86_64-linux-gnu/libc.so.6
COPY --from=builder /usr/lib/x86_64-linux-gnu/libm.so.6 /usr/lib/x86_64-linux-gnu/libm.so.6
COPY --from=builder /usr/share/ca-certificates /usr/share/ca-certificates
COPY --from=builder /etc/ssl/ /etc/ssl/
ENTRYPOINT ["/http-beast-ssl"]

当我在ubuntu容器中运行http-beast-ssl example.com 443 /时,一切都很好。我按预期将HTML放回控制台。

当我在容器内从头开始做同样的事情时,就会出现错误。

那里发生了什么事,我该怎么解决?在我的容器中,是否需要一些东西来使网络按预期工作?那里缺少什么?

以下是C++源代码作为参考:

#include <boost/asio/ssl.hpp>
#include <boost/lexical_cast.hpp>
#include <openssl/cryptoerr.h>
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/ssl.hpp>
#include <boost/beast/version.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ssl/error.hpp>
#include <boost/asio/ssl/stream.hpp>
#include <boost/beast/version.hpp>
#include <openssl/opensslv.h>
#include <cstdlib>
#include <iostream>
#include <string>
namespace beast = boost::beast; // from <boost/beast.hpp>
namespace http = beast::http;   // from <boost/beast/http.hpp>
namespace net = boost::asio;    // from <boost/asio.hpp>
namespace ssl = net::ssl;       // from <boost/asio/ssl.hpp>
using tcp = net::ip::tcp;       // from <boost/asio/ip/tcp.hpp>
// Performs an HTTP GET and prints the response
int main(int argc, char** argv)
{
std::cout << OPENSSL_VERSION_TEXT << std::endl;
try
{
// Check command line arguments.
if(argc != 4 && argc != 5)
{
std::cerr <<
"Usage: http-client-sync-ssl <host> <port> <target> [<HTTP version: 1.0 or 1.1(default)>]n" <<
"Example:n" <<
"    http-client-sync-ssl www.example.com 443 /n" <<
"    http-client-sync-ssl www.example.com 443 / 1.0n";
return EXIT_FAILURE;
}
auto const host = argv[1];
auto const port = argv[2];
auto const target = argv[3];
int version = argc == 5 && !std::strcmp("1.0", argv[4]) ? 10 : 11;
// The io_context is required for all I/O
net::io_context ioc;
// The SSL context is required, and holds certificates
ssl::context ctx(ssl::context::tlsv12_client);
// This holds the root certificate used for verification
ctx.set_default_verify_paths();
// Verify the remote server's certificate
ctx.set_verify_mode(ssl::verify_peer);
// These objects perform our I/O
tcp::resolver resolver(ioc);
beast::ssl_stream<beast::tcp_stream> stream(ioc, ctx);
// Set SNI Hostname (many hosts need this to handshake successfully)
if(! SSL_set_tlsext_host_name(stream.native_handle(), host))
{
beast::error_code ec{static_cast<int>(::ERR_get_error()), net::error::get_ssl_category()};
throw beast::system_error{ec};
}
// Look up the domain name
auto const results = resolver.resolve(host, port);
// Make the connection on the IP address we get from a lookup
beast::get_lowest_layer(stream).connect(results);
// Perform the SSL handshake
stream.handshake(ssl::stream_base::client);
// Set up an HTTP GET request message
http::request<http::string_body> req{http::verb::get, target, version};
req.set(http::field::host, host);
req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
// Send the HTTP request to the remote host
http::write(stream, req);
// This buffer is used for reading and must be persisted
beast::flat_buffer buffer;
// Declare a container to hold the response
http::response<http::dynamic_body> res;
// Receive the HTTP response
http::read(stream, buffer, res);
// Write the message to standard out
std::cout << res << std::endl;
// Gracefully close the stream
beast::error_code ec;
stream.shutdown(ec);
if(ec == net::error::eof)
{
// Rationale:
// http://stackoverflow.com/questions/25587403/boost-asio-ssl-async-shutdown-always-finishes-with-an-error
ec = {};
}
if(ec)
throw beast::system_error{ec};
// If we get here then the connection is closed gracefully
}
catch(boost::system::system_error const& e)
{
auto const& error = e.code();
std::string err = error.message();
if (error.category() == boost::asio::error::get_ssl_category()) {
err = std::string(" (")
+boost::lexical_cast<std::string>(ERR_GET_LIB(error.value()))+","
+boost::lexical_cast<std::string>(ERR_GET_FUNC(error.value()))+","
+boost::lexical_cast<std::string>(ERR_GET_REASON(error.value()))+") ";

//ERR_PACK /* crypto/err/err.h */
char buf[128];
::ERR_error_string_n(error.value(), buf, sizeof(buf));
err += buf;
std::cerr << err << std::endl;
} else {
std::cerr << err << std::endl;
}
return EXIT_FAILURE;
}
return EXIT_SUCCESS;

}

这是我的vcpkg.jsonCMakeLists.txt文件:

{
"name": "mypackage",
"version-string": "0.1.0-dev",
"dependencies": [
"boost-asio",
"boost-beast",
"openssl"
]
}
cmake_minimum_required(VERSION 3.18)
project(beast-test)
set(CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY ON)
set(CMAKE_FIND_USE_CMAKE_SYSTEM_PATH OFF)
set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON)
set(CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH OFF)
find_package(Boost 1.74 REQUIRED COMPONENTS system)
find_package(Threads REQUIRED)
find_package(OpenSSL REQUIRED)
add_executable(http-beast-ssl main2.cpp)
target_link_libraries(http-beast-ssl PRIVATE Threads::Threads Boost::system OpenSSL::SSL OpenSSL::Crypto)

起初,我在一个alpine容器中遇到了同样的问题,即使使用静态链接进行编译,这个问题也会发生。

当在alpine容器中运行curl https://example.com时,它按预期工作,但我的应用程序仍然无法发出http请求。

我知道错误消息说了一些完全无关的东西,但这里的问题(像往常一样(是缺少库。添加这些行以包括DNS库:

COPY --from=builder /usr/lib/x86_64-linux-gnu/libnss_dns.so.2 /usr/lib/x86_64-linux-gnu/libnss_dns.so.2
COPY --from=builder /usr/lib/x86_64-linux-gnu/libresolv.so.2 /usr/lib/x86_64-linux-gnu/libresolv.so.2

这有点像一个常见的抓伤陷阱。我建议您在开发和测试映像时添加所有库,然后重写Dockerfile,只保留必要的库。这样就更容易发现你忘了什么。

更新

我通过将构建器步骤(Ubuntu(中的所有库复制到我的本地机器(./libs(中并将它们安装到最后一个步骤(scratch(中来调试它:

version: "3.7"
services:
test:
build:
context: .
volumes:
- ./libs:/usr/lib/x86_64-linux-gnu

之后,它立即开始工作。所以我开始一个接一个地删除复制的库,直到我再次破坏了图像。这就是我找到所需库的方式。我相信一定有更好的方法可以做到这一点,我只是不熟悉C++。

完整Dockerfile

ARG UBUNTU_VERSION=20.04
FROM ubuntu:${UBUNTU_VERSION} as builder
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get -y install 
curl 
g++-10 
gcc-10 
ninja-build 
unzip 
zip 
make 
perl 
pkg-config 
git 
gdb
RUN mkdir /opt/vcpkg 
&& curl -L -s "https://github.com/microsoft/vcpkg/tarball/8ce7b41302728ff6fc8bd377f572c4cbe8c64c1d" | tar --strip-components=1 -xz -C /opt/vcpkg 
&& /opt/vcpkg/bootstrap-vcpkg.sh
RUN mkdir /opt/cmake && 
curl -s "https://cmake.org/files/v3.18/cmake-3.18.0-Linux-x86_64.tar.gz" | tar --strip-components=1 -xz -C /opt/cmake
RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 10 && 
update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 10
ENV PATH="/opt/cmake/bin:/opt/vcpkg:${PATH}"
RUN mkdir /build2
COPY src /source/src
WORKDIR /build2
RUN cmake /source/src 
-DCMAKE_BUILD_TYPE=Release 
-DCMAKE_GENERATOR=Ninja 
-DCMAKE_MAKE_PROGRAM=/usr/bin/ninja 
-DCMAKE_INSTALL_PREFIX=/install 
-DCMAKE_TOOLCHAIN_FILE=/opt/vcpkg/scripts/buildsystems/vcpkg.cmake
RUN cmake --build . --target all
FROM scratch
COPY --from=builder /build2/http-beast-ssl /http-beast-ssl
COPY --from=builder /lib64/ld-linux-x86-64.so.2 /lib64/ld-linux-x86-64.so.2
COPY --from=builder /usr/lib/x86_64-linux-gnu/libdl.so.2 /usr/lib/x86_64-linux-gnu/libdl.so.2
COPY --from=builder /usr/lib/x86_64-linux-gnu/libpthread.so.0 /usr/lib/x86_64-linux-gnu/libpthread.so.0
COPY --from=builder /usr/lib/x86_64-linux-gnu/libstdc++.so.6 /usr/lib/x86_64-linux-gnu/libstdc++.so.6
COPY --from=builder /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28
COPY --from=builder /usr/lib/x86_64-linux-gnu/libgcc_s.so.1 /usr/lib/x86_64-linux-gnu/libgcc_s.so.1
COPY --from=builder /usr/lib/x86_64-linux-gnu/libc.so.6 /usr/lib/x86_64-linux-gnu/libc.so.6
COPY --from=builder /usr/lib/x86_64-linux-gnu/libm.so.6 /usr/lib/x86_64-linux-gnu/libm.so.6
COPY --from=builder /usr/lib/x86_64-linux-gnu/libnss_dns.so.2 /usr/lib/x86_64-linux-gnu/libnss_dns.so.2
COPY --from=builder /usr/lib/x86_64-linux-gnu/libresolv.so.2 /usr/lib/x86_64-linux-gnu/libresolv.so.2
COPY --from=builder /usr/share/ca-certificates /usr/share/ca-certificates
COPY --from=builder /etc/ssl/ /etc/ssl/
ENTRYPOINT ["/http-beast-ssl"]

相关内容

最新更新