Run a C++ Boost app
In this guide we create and deploy a C++-based HTTP web server using the Boost libraries. To run this example, follow these steps:
-
Install the
kraft
CLI tool and a container runtime engine, e.g. Docker. -
Clone the example repository and
cd
into theexamples/http-cpp-boost/
directory:
git clone https://github.com/kraftcloud/examplescd examples/http-cpp-boost/
Make sure to log into Unikraft Cloud by setting your token and a metro close to you.
We use fra0
(Frankfurt, 🇩🇪) in this guide:
# Set Unikraft Cloud access tokenexport UKC_TOKEN=token# Set metro to Frankfurt, DEexport UKC_METRO=fra0
When done, invoke the following command to deploy this application on Unikraft Cloud:
kraft cloud deploy -p 443:8080 .
The output shows the instance URL and other details:
[●] Deployed successfully! │ ├────────── name: http-cpp-boost-rae7s ├────────── uuid: 5a9886fa-f8a3-4860-afcf-d5eb13fdc38d ├───────── state: running ├─────────── url: https://red-snow-3bn7bzc8.fra0.kraft.host ├───────── image: http-cpp-boost@sha256:61cf86b89fed46351af53689e27189315e466576475f61c7240bf17644613489 ├───── boot time: 15.00 ms ├──────── memory: 128 MiB ├─────── service: red-snow-3bn7bzc8 ├── private fqdn: http-cpp-boost-rae7s.internal ├──── private ip: 172.16.6.4 └────────── args: /http_server
In this case, the instance name is http-cpp-boost-rae7s
and the URL is https://red-snow-3bn7bzc8.fra0.kraft.host
.
They are different for each run.
Use curl
to query the Unikraft Cloud instance of the C++ Boost HTTP web server:
curl https://red-snow-3bn7bzc8.fra0.kraft.host
Hello, World!
At any point in time, you can list information about the instance:
kraft cloud instance list
NAME FQDN STATE CREATED AT IMAGE MEMORY ARGS BOOT TIMEhttp-cpp-boost-rae7s red-snow-3bn7bzc8.fra0.kraft.host running 1 minute ago http-cpp-boost@sha256:61cf86b89fed46351af53689e27189315e... 128 MiB /http_server 15000us
When done, you can remove the instance:
kraft cloud instance remove http-cpp-boost-rae7s
Customize your Application
To customize the application, update the files in the repository, listed below:
http_server.cpp
: the C++ HTTP serverKraftfile
: the Unikraft Cloud specificationDockerfile
: the Docker-specified application filesystem
/*** Compile with: g++ async_http_server.cpp -o async_http_server -lboost_system -lboost_thread -lpthread** https://gist.github.com/danilogr/990efa4ab3b5bce29b883b931ac55507*/
#include <iostream>#include <ostream>#include <istream>#include <ctime>#include <string>#include <functional>#include <boost/asio.hpp>#include <boost/shared_ptr.hpp>#include <boost/enable_shared_from_this.hpp>#include <boost/thread.hpp>
using boost::asio::ip::tcp;
class HttpServer; // forward declaration
class Request : public boost::enable_shared_from_this<Request>{// member variablesHttpServer& server;boost::asio::streambuf request;boost::asio::streambuf response;
void afterRead(const boost::system::error_code& ec, std::size_t bytes_transferred){ // done reading, writes answer (yes, we ignore the request); std::ostream res_stream(&response);
boost::system::error_code err; res_stream << "HTTP/1.0 200 OK\r\n" << "Content-Type: text/html; charset=UTF-8\r\n" << "Content-Length: 14\r\n" << "\r\n" << "Hello, World!\n" << "\r\n"; boost::asio::async_write(*socket, response, boost::bind(&Request::afterWrite, shared_from_this(), err, bytes_transferred));}
void afterWrite(const boost::system::error_code& ec, std::size_t bytes_transferred){ // done writing, closing connection socket->close();}
public:
boost::shared_ptr<tcp::socket> socket;Request(HttpServer& server);void answer(){ if (!socket) return;
// reads request till the end boost::system::error_code err; boost::asio::async_read_until(*socket, request, "\r\n\r\n", boost::bind(&Request::afterRead, shared_from_this(), err, 0));}};
class HttpServer{public:
HttpServer(unsigned int port) : acceptor(io_service, tcp::endpoint(tcp::v4(), port)) {} ~HttpServer() { if (sThread) sThread->join(); }
void Run() { sThread.reset(new boost::thread(boost::bind(&HttpServer::thread_main, this))); }
boost::asio::io_service io_service;
private: tcp::acceptor acceptor; boost::shared_ptr<boost::thread> sThread;
void thread_main() { // adds some work to the io_service start_accept(); io_service.run(); } void start_accept() { boost::system::error_code err; boost::shared_ptr<Request> req (new Request(*this)); acceptor.async_accept(*req->socket, boost::bind(&HttpServer::handle_accept, this, req, err)); }
void handle_accept(boost::shared_ptr<Request> req, const boost::system::error_code& error) { if (!error) { req->answer(); } start_accept(); }};
Request::Request(HttpServer& server): server(server){socket.reset(new tcp::socket(server.io_service));}
int main(){HttpServer server(8080);server.Run();}}
spec: v0.6
runtime: base:latest
rootfs: ./Dockerfile
cmd: ["/http_server"]
FROM --platform=linux/x86_64 debian:bookworm AS build
RUN set -xe ; \apt -yqq update ; \apt -yqq install build-essential ; \apt -yqq install libboost-all-dev
WORKDIR /src
COPY ./http_server.cpp /src/http_server.cpp
RUN set -xe; \g++ \-Wall -Wextra \-fPIC -pie \-o /http_server http_server.cpp \-lboost_system -lboost_thread -lpthread
FROM scratch
# System / C++ librariesCOPY --from=build /lib/x86_64-linux-gnu/libboost_thread.so.1.74.0 /lib/x86_64-linux-gnu/libboost_thread.so.1.74.0COPY --from=build /lib/x86_64-linux-gnu/libstdc++.so.6 /lib/x86_64-linux-gnu/libstdc++.so.6COPY --from=build /lib/x86_64-linux-gnu/libgcc_s.so.1 /lib/x86_64-linux-gnu/libgcc_s.so.1COPY --from=build /lib/x86_64-linux-gnu/libc.so.6 /lib/x86_64-linux-gnu/libc.so.6COPY --from=build /lib/x86_64-linux-gnu/libm.so.6 /lib/x86_64-linux-gnu/libm.so.6COPY --from=build /lib64/ld-linux-x86-64.so.2 /lib64/ld-linux-x86-64.so.2
# C++ HTTP serverCOPY --from=build /http_server /http_server
Lines in the Kraftfile
have the following roles:
-
spec: v0.6
: The currentKraftfile
specification version is0.6
. -
runtime: base
: The Unikraft runtime kernel to use is its base one. -
rootfs: ./Dockerfile
: Build the application root filesystem using theDockerfile
. -
cmd: ["/http_server"]
: Use/http_server
as the starting command of the instance.
Lines in the Dockerfile
have the following roles:
COPY ./http_server.cpp /src/http_server.cpp
: Copy the server implementation file (http_server.cpp
) in the Docker filesystem (in/src/http_server.cpp
).
The following options are available for customizing the application:
-
If only updating the implementation in the
http_server.cpp
source file, no other change is required. -
If new files are added, these have to be copied in the application filesystem, using the
COPY
command in theDockerfile
. -
If a new C++ source files is added, update the
cmd
line in theKraftfile
and replacehttp_server.cpp
to run that file when creating the instance. -
More extensive changes may require expanding the
Dockerfile
with additionalDockerfile
commands.
Learn More
Use the --help
option for detailed information on using Unikraft Cloud:
kraft cloud --help
Or visit the CLI Reference.