Skip to content

Latest commit

 

History

History
210 lines (167 loc) · 6.3 KB

HOWTO.md

File metadata and controls

210 lines (167 loc) · 6.3 KB

Trying it out

For a quick and simple 'hello world' experience, you can use docker with

$ make docker

which will create two images:

  1. unit:wasm (based on the Docker Official image, with Wasm Module)
  2. unit:demo-wasm (based on the Wasm image, with demo application)

Manual build instructions below.

Prerequisites and Assumptions

You will need:

  • Modern Linux platform (might work on others, not yet tested).
  • Ability to build Unit from source. If you haven't done this before, please first run through the Building From Source how-to guide.
  • Additional build tools (required for the demo Wasm Module)
    • clang
    • llvm
    • lld

Building the Wasm Language Module

  1. Do a test build of Unit from source (see docs) with this PR/patch applied. The following steps assume you're starting in the unit directory and used ./configure --prefix=$PWD/build.

  2. Download and extract the Wasmtime C API (newer versions may or may not work). Notice that we use $(arch) to substitute-in the appropriate CPU architecture. This works for x86_64 and aarch64 (ARM) platforms.

wget -O- https://github.com/bytecodealliance/wasmtime/releases/download/v11.0.0/wasmtime-v11.0.0-$(arch)-linux-c-api.tar.xz | tar Jxfv -
  1. Configure the Wasm Language Module for Unit
./configure wasm --include-path=$PWD/wasmtime-v11.0.0-$(arch)-linux-c-api/include \
                 --lib-path=$PWD/wasmtime-v11.0.0-$(arch)-linux-c-api/lib --rpath
  1. Build the Wasm Language Module
make
  1. Test that unitd Can Load the Language Module

Run unitd in the foreground (attached to the console) to check that Unit can discover and load the wasm Language Module at startup. You should see console output similar to this:

$ $PWD/build/sbin/unitd --no-daemon --log /dev/stderr
2023/06/15 11:29:31 [info] 1#1 unit 1.31.0 started
2023/06/15 11:29:31 [info] 43#43 discovery started
2023/06/15 11:29:31 [notice] 43#43 module: wasm 0.1 "/path/to/modules/wasm.unit.so"

Building the demo application

From a suitable directory...

Clone the unit-wasm repository

$ git clone https://github.com/nginx/unit-wasm.git

Download and extract the wasi-sysroot from the WASI SDK

wget -O- https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-20/wasi-sysroot-20.0.tar.gz | tar zxfv -

Next Compile the C demo Wasm Modules to .wasm files. This requires at least the following; make and clang, llvm, compiler-rt, and lld from LLVM 9.0+

$ cd unit-wasm
$ make WASI_SYSROOT=../wasi-sysroot examples

If the above fails like

wasm-ld: error: cannot open /usr/lib/llvm-11/lib/clang/11.0.1/lib/wasi/libclang_rt.builtins-wasm32.a: No such file or directory
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Then you need to download the wasm32 clang runtime and copy it into the location mentioned in the error message.

E.g

In the above case we would untar libclang_rt.builtins-wasm32-wasi-20.0.tar.gz into /usr/lib/llvm-11/lib/clang/11.0.1/

On Fedora this would be more like /usr/lib64/clang/16/

Adjust the tar '-C ...' option accordingly below...

wget -O- https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-20/libclang_rt.builtins-wasm32-wasi-20.0.tar.gz | sudo tar -xvzf - -C /usr/lib/llvm-11/lib/clang/11.0.1

With recent enough versions of Clang (that support the -print-runtime-dir option) you can use the following command (as root)

wget -O- https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-20/libclang_rt.builtins-wasm32-wasi-20.0.tar.gz | tar --strip-components=1 -xvzf - -C $(dirname $(clang -print-runtime-dir))

Then try again...

If everything built OK then you should have the following two WASM modules

examples/c/luw-echo-request.wasm
examples/c/luw-upload-reflector.wasm

Configure Unit to run the demo application

  {
    "listeners": {
        "[::1]:8080": {
            "pass": "routes"
        }
    },

    "settings": {
        "http": {
            "max_body_size": 1073741824
        }
    },

    "routes": [
        {
            "match": {
                "uri": "/echo*"
            },
            "action": {
                "pass": "applications/luw-echo-request"
            }
        },
        {
            "match": {
                "uri": "/upload*"
            },
            "action": {
                "pass": "applications/luw-upload-reflector"
            }
        }
    ],

    "applications": {
        "luw-echo-request": {
            "type": "wasm",
            "module": "/path/to/unit-wasm/examples/c/luw-echo-request.wasm",
            "request_handler": "luw_request_handler",
            "malloc_handler": "luw_malloc_handler",
            "free_handler": "luw_free_handler",
            "module_init_handler": "luw_module_init_handler",
            "module_end_handler": "luw_module_end_handler",
            "access": {
                "filesystem": [
                    "/tmp",
                    "/foo/bar"
                ]
            }
        },
        "luw-upload-reflector": {
            "type": "wasm",
            "module": "/path/to/unit-wasm/examples/c/luw-upload-reflector.wasm",
            "request_handler": "luw_request_handler",
            "malloc_handler": "luw_malloc_handler",
            "free_handler": "luw_free_handler",
            "request_end_handler": "luw_request_end_handler",
            "response_end_handler": "luw_response_end_handler"
        }
    }
}

Apply the above configuration to the /config URI of Unit's Control API. With the JSON in a file, you can use the CLI to apply it.

cat conf.json | tools/unitc /config

The following messages should then appear in the Unit log file (or console if running with --no-daemon).

2023/07/26 13:28:14 [info] 182585#182585 "luw-echo-request" prototype started
2023/07/26 13:28:14 [info] 182590#182590 "luw-echo-request" application started
2023/07/26 13:28:14 [info] 182591#182591 "luw-upload-reflector" prototype started
2023/07/26 13:28:14 [info] 182596#182596 "luw-upload-reflector" application started

Now make a request to the demo application.

curl http://localhost:8080/echo