设备或资源在容器中从头开始和高山忙,但不在 ubuntu 上
问题:设备或资源在容器中从头开始和高山忙,但不在 ubuntu 上 我编辑了这个问题,但我的问题体现在一个高山容器中。我现在从头开始在容器中遇到同样的问题。这是同一个问题,但范围更窄。 正如标题所描述的,我在 Ubuntu 容器中有一个工作可执行文件,用于构建我的应用程序,但是一旦我将它复制到 Alpine 容器中,我得到Device or resource busy具有相同的可执行文件,我对发生
问题:设备或资源在容器中从头开始和高山忙,但不在 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.0\n";
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.json
和CMakeLists.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)并将它们安装到最终(临时)步骤中来调试它:
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"]
更多推荐
所有评论(0)