Demystify GNU Artanis service deployment in product environment

GNU Artanis is not limited to building web applications and websites, it can be used for much more. Recently, I contributed to the system integration testing for a smart factory project, and I’d like to share the process in this post.

While a full system integration test in a production environment can be complex, this post simplifies the process, making it more accessible and easier to reproduce. In the final section, I address cybersecurity concerns and outline some of the solutions I implemented. Additionally, I provide a simple benchmark for the performance of the RESTful API after enabling the Linux Kernel Vaccine.

Due to confidentiality concerns from our partners, I am unable to disclose the complete benchmarking results. However, I believe the information presented here is sufficient to understand the general performance improvements and the impact of the security enhancements.

In this post, I will not mention any non-free product, or even I mentioned any libre-licensed product, it doesn't mean I advocate it. You can always find option, and I may list the existing alternatives.

The OS and hardware

In a production environment, my OS experience spans Debian, Ubuntu, Red Hat, and SUSE, allowing you the flexibility to choose the others you prefer. In this post, we use Ubuntu 24.04 live server ISO.

I tested it under Intel. If you conduct this test on a different hardware platform, I would greatly appreciate your feedback. Feel free to reach out via email at [email protected].

Prepare the environment

What do we need?

  • Nginx serves as a reverse proxy and handles static file delivery.
  • Guile-3.0 as the Scheme compiler for GNU Artanis.
  • GNU Artanis-1.0.0
  • byggsteg for the API gateway performance test.

So what is byggsteg?

Byggsteg is a CI/CD project written in Guile Scheme, which I recently ported to GNU Artanis 1.0.0. Choosing an existing libre-licensed project for this system integration test was a practical and logical decision.

Install dependencies

For Artanis-1.0.0, here're the critical dependencies and their versions:

  • guile-3.0.9
  • guile-dbi-2.1.8
  • guile-dbd-mysql-2.1.8
  • guile-curl-0.9
  • guile-redis-2.2.0
  • guile-json-4.7.3
sudo apt install texinfo guile-3.0 guile-3.0-dev build-essential automake git
sudo apt install autoconf libtool libmariadb-dev-compat libmariadb-dev libnss3
sudo apt install libnss3-dev gettext redis redis-server libcurl4-openssl-dev
sudo apt install nginx

guile-dbi-2.1.8 and guile-dbd-mysql-2.1.8

Since these two dependencies are in the same repo, we build them in a row.

git clone https://github.com/opencog/guile-dbi.git
cd guile-dbi
git checkout guile-dbi-2.1.8
cd guile-dbi
./autogen.sh
./configure --prefix=/usr
make -j5
sudo make install
ldconfig
cd ..

git checkout guile-dbd-mysql-2.1.8
cd guile-dbd-mysql
./autogen.sh
./configure --prefix=/usr
make -j5
sudo make install
sudo ldconfig

guile-curl-0.9

git clone https://github.com/spk121/guile-curl.git
cd guile-curl
git checkout v0.9
./bootstrap && ./configure --prefix=/usr
make -j5
sudo make install
sudo ln -s /usr/lib/guile/3.0/extensions/libguile-curl.* /usr/lib/
sudo ldconfig

Please note that you need to make the soft link under Debian/Ubuntu. Otherwise the lib may not be recognized.

guile-redis-2.2.0

git clone https://github.com/aconchillo/guile-redis.git
cd guile-redis
git checkout -b 2.2.0
autoreconf -vif
./configure --prefix=/usr
make -j5
sudo make install
sudo ldconfig

guile-json-4.7.3

git clone https://github.com/aconchillo/guile-json.git
cd guile-json
git checkout -b 4.7.3
autoreconf -iv
./configure --prefix=/usr
make -j5
sudo make install
sudo ldconfig

Build GNU Artanis-1.0.0

wget -c https://ftp.gnu.org/gnu/artanis/artanis-1.0.0.tar.gz
tar -zxvf artanis-1.0.0.tar.gz
cd artanis-1.0.0
./autogen.sh # don't miss this step, otherwise there's no configure script
mkdir -p build
cd build
../configure --prefix=/usr
make -j5
sudo make install

Configuration

Nginx

For this post, we simplified the config for localhost.

server {

    listen 80;
    server_name localhost;

    root /var/www/byggsteg/pub;

    index /;

    server_name localhost:

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_pass_header Server;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    location ~* \.(?:gif|jpg|jpeg|png|bmp|swf|ico|eof|woff|html|svg|bz2|ttf|TTF)$
    {
        expires      30d;
    }

    location ~* \.(?:js|css)$
    {
        expires      12h;
    }
}

GNU Artanis

Edit conf/artanis.conf, find these items and change:

server.wqlen = 64
server.polltimeout = 10
server.bufsize = 12288
server.nginx = true

The meaning of these configs is out of the topic of this post.

CDN [optional]

If you deploy the service on the Internet, I recommend using a CDN. While I won’t endorse any specific provider, there are plenty of options available to choose from.

In my setup, I only cache static files such as PNG, CSS, and JS. You’ll need to configure rules to ensure that URLs requiring dynamic handling by GNU Artanis are excluded from caching.

Security enhancement

Cybersecurity is a complex and multifaceted topic. While the HardenedLinux community provides a robust security enhancement profile as a baseline, detailing it here would go against my goal of presenting a minimal and easily reproducible process.

In this post, we focus on the key aspect of the security enhancement: the Linux Kernel Vaccine. I will conduct and compare API stress tests before and after applying the Vaccine.

The Vaccine related performance tested RESTful API should remain unaffected by Nginx or the CDN.

Linux Kernel Vaccine

The Linux Kernel Vaccine represents a new frontier in cybersecurity technology, and its purpose is evident from the name. Currently, there are several implementations of the Linux Kernel Vaccine in the industry, but a detailed comparison among them is beyond the scope of this post.

In our production environment, we choose VED (Vault Exploit Defense) for the Linux Kernel Vaccine, which is licensed under GPLv2.0. If you’re interested, a community version is available through the HardenedLinux community.

In this system integration test, We are able to test with the full version of VED with commertial permission which is largely improved compared to the community version. And it's also GPLv2.0. However, we're not going to reveal the full version code according to this basic rule of GPL.

A notable libre-licensed alternative is GrSecurity, in case you're interested in.

So far, we have showed the best practice of deploying GNU Artanis in a production environment. The next chapter is not for

Performance benchmark [optional]

NOTE: This test is only for the GNU Artanis server core without Nginx or CDN.

Machine, OS and environment

We're not going to advocate the cloud provider, but we can tell you the machine configuration.

  • Intel(R) Xeon(R) CPU E5-2686 v4 @ 2.30GHz
    • 2 CPU cores
  • RAM 8GB
  • Ubuntu 24.04 live server
    • Linux 6.8.0-1021
  • GNU Guile 3.0.9
  • GNU Artanis 1.0.0

Enable multi.server feature

The benchmark test is based on the multi server feature of GNU Artanis for best throughput performance.

In this benchmark, we set the multi server instances to 2 since the cloud machine has only 2 CPU cores. We also compare the throughput with the unique instance case.

server.multi = true

The multi.server can let you start multiple GNU Artanis instances to handle the requests concurrently. This feature is essential for high-performance web applications. However, one may have to manage each instance by manually, it's a bit tricky since it's designed for distributed situation.

NOTE: If you're looking for an easy setup for higher performance in just one instance, there's experimental **server.workers feature in the coming v1.1.0.**

The benchmark purpose

First, let me define the purpose of this benchmark. According to our experiences, after enabled the Linux Kernel Vaccine, some of the performance will be affacted, for example I/O. So we have to make sure the performance of GNU Artanis will not be down too much under Linux Kernel Vaccine.

Do we need to tune the kernel prarameters?

I don't think so. Tuning kernel parameters is a complex task. Without careful research and adjustment, simple tweaks can potentially degrade performance. In this post, the benchmark is designed to compare the differences between the pre- and post-vaccine stages. The kernel parameters tuning is out of the topic, but could be further discussed in another post.

Specifically, I enabled the multi-server mode in GNU Artanis, which is a feature that allows multiple threads to handle coroutine workqueues concurrently. This feature is essential for high-performance web applications.

Clone byggsteg

In this post, we put byggsteg into /var/www, this will affect the Nginx config file later.

sudo apt install wrk # for the benchmark

git clone https://codeberg.org/jjba23/byggsteg.git
cd byggsteg
make create # will ask for authenication, please input the password, feel free the check the Makefile for the details
make prepare-dirs

# run with tmux or screen
tmux new -t byggsteg
art work
# ctrl+b d to detach

# restore the session
# tmux a -t byggsteg

The benchmark

We're going to test the API performance with 100 long connections, 10 threads, and 20 seconds duration. The brief meaning of the API is to check the building instance log and return a json response. Before the test, we need to start an instance with byggsteg.

curl 'localhost:3000/api/v1/jobs/manage/submit' -X POST -H 'Content-Type: application/x-www-form-urlencoded' \
     --data-urlencode 'job-code=`((project . "free-alacarte")(branch-name . "trunk")(task . "stack-test")(clone-url . "https://codeberg.org/jjba23/free-alacarte"))'
# ==> response a json
# {"log-filename":"667265652d616c6163617274655f5f31323a34303a34345f5f32382d31322d323032342e62796767737465672e6c6f670a"}

According to the response, we can get the log file name, and we can use it to check the log. The API usage is trivial in this post, if you're interested, please visit the byggsteg project.

Now let's test the performance of the API.

wrk -c 100 -t 10 -d20s --latency http://localhost:3000/api/v1/logs/667265652d616c6163617274655f5f31323a34303a34345f5f32382d31322d323032342e62796767737465672e6c6f670a

# the response will be like this json
# {"success":"true","failure":"false","in-progress":"false","log-filename":"free-alacarte__12:40:44__28-12-2024.byggsteg.log","log-data":"0a7374617274696e67206e6577206a6f622e2e2e0a0a0a"}

Unique instance

  • Without Linux Kernel Vaccine (VED)
    Running 20s test @ http://localhost:3000/api/v1/logs/667265652d616c6163617274655f5f31323a34303a34345f5f32382d31322d323032342e62796767737465672e6c6f670a
      10 threads and 100 connections
      Thread Stats   Avg      Stdev     Max   +/- Stdev
        Latency   462.23ms  182.24ms 794.22ms   59.34%
        Req/Sec    29.55     24.81   191.00     76.59%
      Latency Distribution
         50%  460.47ms
         75%  617.11ms
         90%  713.63ms
         99%  773.00ms
      4274 requests in 20.05s, 1.44MB read
    Requests/sec:    213.16
    Transfer/sec:     73.48KB
    
  • With Linux Kernel Vaccine (VED)
    Running 20s test @ http://localhost:3000/api/v1/logs/667265652d616c6163617274655f5f31323a34303a34345f5f32382d31322d323032342e62796767737465672e6c6f670a
      10 threads and 100 connections
      Thread Stats   Avg      Stdev     Max   +/- Stdev
        Latency   497.41ms  199.72ms 887.80ms   60.05%
        Req/Sec    28.21     22.37   111.00     78.12%
      Latency Distribution
         50%  499.25ms
         75%  665.73ms
         90%  768.93ms
         99%  832.29ms
      3970 requests in 20.05s, 1.34MB read
    Requests/sec:    198.03
    Transfer/sec:     68.27KB
    

    The performance was reduced around 7% with Linux Kernel Vaccine.

Multi instances = 2

  • Without Linux Kernel Vaccine (VED)
    Running 20s test @ http://localhost:3000/api/v1/logs/667265652d616c6163617274655f5f31323a34303a34345f5f32382d31322d323032342e62796767737465672e6c6f670a
      10 threads and 100 connections
      Thread Stats   Avg      Stdev     Max   +/- Stdev
        Latency   378.10ms  398.30ms   1.93s    82.01%
        Req/Sec    59.04     55.22   303.00     78.40%
      Latency Distribution
         50%  322.70ms
         75%  649.01ms
         90%  962.45ms
         99%    1.45s
      6946 requests in 20.05s, 2.34MB read
    Requests/sec:    346.49
    Transfer/sec:    119.44KB
    
  • With Linux Kernel Vaccine (VED)
    Running 20s test @ http://localhost:3000/api/v1/logs/667265652d616c6163617274655f5f31323a34303a34345f5f32382d31322d323032342e62796767737465672e6c6f670a
      10 threads and 100 connections
      Thread Stats   Avg      Stdev     Max   +/- Stdev
        Latency   406.81ms  444.74ms   1.98s    82.23%
        Req/Sec    58.04     54.69   320.00     77.38%
      Latency Distribution
         50%  330.33ms
         75%  707.31ms
         90%    1.07s
         99%    1.61s
      6553 requests in 20.05s, 2.21MB read
      Socket errors: connect 0, read 0, write 0, timeout 15
    Requests/sec:    326.82
    Transfer/sec:    112.66KB
    

    The performance was reduced around 5% with Linux Kernel Vaccine.

Conclusion

The tested byggsteg code is not a fast implementation, there're frequent disk I/O operations, and we don't set any memory cache intendedly. The purpose of this test is to show the performance (included I/O, string parsing and JIT) difference before and after enabling the Linux Kernel Vaccine.

The performance of GNU Artanis was reduced by around 5%~7% after enabling the VED Linux Kernel Vaccine. This result is within the expected range, and the performance is still acceptable for a production environment. Considering the security enhancements provided by the Vaccine, the trade-off is reasonable.

There's also ARM64 benchmark you may want to take a look.

Feedback please!

Comments are welcome, you may send mail to [email protected]. Happy hacking!

Author: Nala Ginrut

Created: 2024-12-31 Tue 02:10

Validate