Skip to content
This repository has been archived by the owner on Mar 4, 2024. It is now read-only.

Commit

Permalink
Add Makefile, configuration files and scripts
Browse files Browse the repository at this point in the history
Update the README with instructions on setting up, configuring, building
and running the Nginx app with Unikraft. As part of it, add Makefile
files, configuration files and scripts; they are referenced in the
`README.md` file.

Current instructions cover the use of QEMU/KVM platform (both on x86_64 and
on AArch64) and GCC. Firecraker/KVM, Xen, Linux platforms and Clang are
not yet documented.

Signed-off-by: Razvan Deaconescu <razvand@unikraft.io>
Reviewed-by: Stefan Jumarea <stefanjumarea02@gmail.com>
Approved-by: Stefan Jumarea <stefanjumarea02@gmail.com>
Tested-by: Unikraft CI <monkey@unikraft.io>
GitHub-Closes: #13
  • Loading branch information
razvand authored and unikraft-bot committed Jul 1, 2023
1 parent dfab6b2 commit d69f1ab
Show file tree
Hide file tree
Showing 7 changed files with 1,257 additions and 62 deletions.
9 changes: 9 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
UK_ROOT ?= $(PWD)/.unikraft/unikraft
UK_LIBS ?= $(PWD)/.unikraft/libs
LIBS := $(UK_LIBS)/musl:$(UK_LIBS)/lwip:$(UK_LIBS)/nginx

all:
@$(MAKE) -C $(UK_ROOT) A=$(PWD) L=$(LIBS)

$(MAKECMDGOALS):
@$(MAKE) -C $(UK_ROOT) A=$(PWD) L=$(LIBS) $(MAKECMDGOALS)
1 change: 1 addition & 0 deletions Makefile.uk
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
$(eval $(call addlib,appnginx))
356 changes: 294 additions & 62 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,93 +1,325 @@
# Nginx on Unikraft

This application starts an NginX web server.
This application starts an Nginx web server with Unikraft.
Follow the instructions below to set up, configure, build and run Nginx.

To configure, build and run the application you need to have [kraft](https://github.com/unikraft/kraft) installed.
## Requirements

To be able to interact with the web server, configure the application to run on the KVM platform:
```
$ kraft configure -p kvm -m x86_64
```
In order to set up, configure, build and run Nginx on Unikraft, the following packages are required:

Build the application:
```
$ kraft build
```
* `build-essential` / `base-devel` / `@development-tools` (the meta-package that includes `make`, `gcc` and other development-related packages)
* `sudo`
* `flex`
* `bison`
* `git`
* `wget`
* `uuid-runtime`
* `qemu-system-x86`
* `qemu-system-arm`
* `qemu-kvm`
* `sgabios`
* `gcc-aarch64-linux-gnu`

GCC >= 8 is required to build Nginx on Unikraft.

We use a virtual bridge to create a connection between the VM and the host system.
We assign address `172.44.0.1/24` to the bridge interface (pointing to the host) and we assign address `172.44.0.2/24` to the virtual machine, by passing boot arguments.
The IP addresses are of our choosing, they can be changed to other values.
On Ubuntu/Debian or other `apt`-based distributions, run the following command to install the requirements:

We run the commands below to create and assign the IP address to the bridge `virbr0` (once again, our choice of name; any name works):
```console
$ apt-get install -y --no-install-recommends \
build-essential \
sudo \
gcc-aarch64-linux-gnu \
libncurses-dev \
libyaml-dev \
flex \
bison \
git \
wget \
uuid-runtime \
qemu-kvm \
qemu-system-x86 \
qemu-system-arm \
sgabios
```
$ sudo brctl addbr virbr0
$ sudo ip a a 172.44.0.1/24 dev virbr0
$ sudo ip l set dev virbr0 up

Running Nginx Unikraft with QEMU requires networking support.
For this to work properly a specific configuration must be enabled for QEMU.
Run the commands below to enable that configuration (for the network bridge to work):

```console
$ sudo mkdir /etc/qemu/
$ echo "allow all" | sudo tee /etc/qemu/bridge.conf
```

We can check the proper configuration:
## Set Up

The following repositories are required for Nginx:

* The application repository (this repository): [`app-nginx`](https://github.com/unikraft/app-nginx)
* The Unikraft core repository: [`unikraft`](https://github.com/unikraft/unikraft)
* Library repositories:
* The Nginx "library" repository: [`lib-nginx`](https://github.com/unikraft/lib-nginx)
* The standard C library: [`lib-musl`](https://github.com/unikraft/lib-musl)
* The networking stack library: [`lib-lwip`](https://github.com/unikraft/lib-lwip)

Follow the steps below for the setup:

1. First clone the [`app-nginx` repository](https://github.com/unikraft/app-nginx) in the `nginx/` directory:

```console
$ git clone https://github.com/unikraft/app-nginx nginx
```

Enter the `nginx/` directory:

```console
$ cd nginx/

$ ls -F
config-qemu-aarch64 config-qemu-x86_64 fs0/ kraft.yaml Makefile Makefile.uk README.md run-qemu-aarch64.sh* run-qemu-x86_64.sh*
```

1. While inside the `nginx/` directory, create the `.unikraft/` directory:

```console
$ mkdir .unikraft
```

Enter the `.unikraft/` directory:

```console
$ cd .unikraft/
```

1. While inside the `.unikraft` directory, clone the [`unikraft` repository](https://github.com/unikraft/unikraft):

```console
$ git clone https://github.com/unikraft/unikraft unikraft
```

1. While inside the `.unikraft/` directory, create the `libs/` directory:

```console
$ mkdir libs
```

1. While inside the `.unikraft/` directory, clone the library repositories in the `libs/` directory:

```console
$ git clone https://github.com/unikraft/lib-nginx libs/nginx

$ git clone https://github.com/unikraft/lib-musl libs/musl

$ git clone https://github.com/unikraft/lib-lwip libs/lwip
```

1. Get back to the application directory:

```console
$ cd ../
```

Use the `tree` command to inspect the contents of the `.unikraft/` directory.
It should print something like this:

```console
$ tree -F -L 2 .unikraft/
.unikraft/
|-- libs/
| |-- lwip/
| |-- musl/
| `-- nginx/
`-- unikraft/
|-- arch/
|-- Config.uk
|-- CONTRIBUTING.md
|-- COPYING.md
|-- include/
|-- lib/
|-- Makefile
|-- Makefile.uk
|-- plat/
|-- README.md
|-- support/
`-- version.mk

10 directories, 7 files
```

## Configure

Configuring, building and running a Unikraft application depends on our choice of platform and architecture.
Currently, supported platforms are QEMU (KVM), Xen and linuxu.
QEMU (KVM) is known to be working, so we focus on that.

Supported architectures are x86_64 and AArch64.

Use the corresponding the configuration files (`config-...`), according to your choice of platform and architecture.

### QEMU x86_64

Use the `config-qemu-x86_64` configuration file together with `make defconfig` to create the configuration file:

```console
$ UK_DEFCONFIG=$(pwd)/config-qemu-x86_64 make defconfig
```
$ ip a s virbr0
420: virbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1000
link/ether 3a:3e:88:e6:a1:e4 brd ff:ff:ff:ff:ff:ff
inet 172.44.0.1/24 scope global virbr0
valid_lft forever preferred_lft forever
inet6 fe80::383e:88ff:fee6:a1e4/64 scope link
valid_lft forever preferred_lft forever

This results in the creation of the `.config` file:

```console
$ ls .config
.config
```

Now we start the virtual machine and pass it the proper arguments to assing the IP address `172.44.0.2/24`:
The `.config` file will be used in the build step.

### QEMU AArch64

Use the `config-qemu-aarch64` configuration file together with `make defconfig` to create the configuration file:

```console
$ UK_DEFCONFIG=$(pwd)/config-qemu-aarch64 make defconfig
```
$ kraft run -b virbr0 "netdev.ipv4_addr=172.44.0.2 netdev.ipv4_gw_addr=172.44.0.1 netdev.ipv4_subnet_mask=255.255.255.0 --"

Similar to the x86_64 configuration, this results in the creation of the `.config` file that will be used in the build step.

## Build

Building uses as input the `.config` file from above, and results in a unikernel image as output.
The unikernel output image, together with intermediary build files, are stored in the `build/` directory.

### Clean Up

Before starting a build on a different platform or architecture, you must clean up the build output.
This may also be required in case of a new configuration.

Cleaning up is done with 3 possible commands:

* `make clean`: cleans all actual build output files (binary files, including the unikernel image)
* `make properclean`: removes the entire `build/` directory
* `make distclean`: removes the entire `build/` directory **and** the `.config` file

Typically, you would use `make properclean` to remove all build artifacts, but keep the configuration file.

### QEMU x86_64

Building for QEMU x86_64 assumes you did the QEMU x86_64 configuration step above.
Build the Unikraft Nginx image for QEMU x86_64 by using the command below:

```console
$ make -j $(nproc)
[...]
0: Set IPv4 address 172.44.0.2 mask 255.255.255.0 gw 172.44.0.1
en0: Added
en0: Interface is up
LD nginx_qemu-x86_64.dbg
UKBI nginx_qemu-x86_64.dbg.bootinfo
SCSTRIP nginx_qemu-x86_64
GZ nginx_qemu-x86_64.gz
make[1]: Leaving directory '/media/razvan/c4f6765a-efa5-4ebd-9cf0-7da9908a0189/razvan/unikraft/solo/nginx/.unikraft/unikraft'
```

At the end of the build command, the `nginx_qemu-x86_64` unikernel image is generated.
This image is to be used in the run step.

### QEMU AArch64

If you had configured and build a unikernel image for another platform or architecture (such as x86_64) before, then:

1. Do a cleanup step with `make properclean`.

1. Configure for QEMU AAarch64, as shown above.

1. Follow the instructions below to build for QEMU AArch64.

Building for QEMU AArch64 assumes you did the QEMU AArch64 configuration step above.
Build the Unikraft Nginx image for QEMU AArch64 by using the same command as for x86_64:

```console
$ make -j $(nproc)
[...]
LD nginx_qemu-arm64.dbg
UKBI nginx_qemu-arm64.dbg.bootinfo
SCSTRIP nginx_qemu-arm64
GZ nginx_qemu-arm64.gz
make[1]: Leaving directory '/media/razvan/c4f6765a-efa5-4ebd-9cf0-7da9908a0189/razvan/unikraft/solo/nginx/.unikraft/unikraft
```

The boot message confirms the assigning of the `172.44.0.2/24` IP address to the virtual machine.
We use `wget` to validate it's working properly and we are able to get the `index.html` file:
Similarly to x86_64, at the end of the build command, the `nginx_qemu-arm64` unikernel image is generated.
This image is to be used in the run step.

## Run

Run the resulting image with the `run-...` scripts.

### QEMU x86_64

To run the QEMU x86_64 build, use `run-qemu-x86_64.sh`:

```console
$ ./run-qemu-x86_64.sh
qemu-system-x86_64: warning: TCG doesn't support requested feature: CPUID.01H:ECX.vmx [bit 5]
1: Set IPv4 address 172.44.0.2 mask 255.255.255.0 gw 172.44.0.1
en1: Added
en1: Interface is up
Powered by
o. .o _ _ __ _
Oo Oo ___ (_) | __ __ __ _ ' _) :_
oO oO ' _ `| | |/ / _)' _` | |_| _)
oOo oOO| | | | | (| | | (_) | _) :_
OoOoO ._, ._:_:_,\_._, .__,_:_, \___)
Atlas 0.13.1~5eb820bd
```

The server listens for connections on the `172.44.0.2` address advertised.
A web client (such as `wget`) is required to query the server.

Open another console and use the `wget` command below to query the server:

```console
$ wget 172.44.0.2
--2021-08-18 16:47:38-- http://172.44.0.2/
--2023-07-01 13:53:24-- http://172.44.0.2/
Connecting to 172.44.0.2:80... connected.
HTTP request sent, awaiting response... 200 OK
[...]
2021-08-18 16:47:38 (41.5 MB/s) - ‘index.html’ saved [160]
```
Length: 180 [text/html]
Saving to: ‘index.html’

Cleaning up means closing the virtual machine (and the HTTP server) and disabling and deleting the bridge interface:
```
$ sudo ip l set dev virbr0 down
$ sudo brctl delbr virbr0
index.html 100%[================================================================================================>] 180 --.-KB/s in 0s

2023-07-01 13:53:25 (12.6 MB/s) - ‘index.html’ saved [180/180]
```

If you want to have more control you can also configure, build and run the application manually.
To close the QEMU Nginx server, use the `Ctrl+a x` keyboard shortcut;
that is press the `Ctrl` and `a` keys at the same time and then, separately, press the `x` key.

To configure it for the KVM platform:
```
$ make menuconfig
```
### QEMU AArch64

Build the application:
```
$ make
```
To run the AArch64 build, use `run-qemu-aarch64.sh`:

Run the application:
```
sudo qemu-system-x86_64 -fsdev local,id=myid,path=$(pwd)/fs0,security_model=none \
-device virtio-9p-pci,fsdev=myid,mount_tag=fs0,disable-modern=on,disable-legacy=off \
-netdev bridge,id=en0,br=virbr0 \
-device virtio-net-pci,netdev=en0 \
-kernel "build/app-nginx_kvm-x86_64" \
-append "netdev.ipv4_addr=172.44.0.2 netdev.ipv4_gw_addr=172.44.0.1 netdev.ipv4_subnet_mask=255.255.255.0 --" \
-cpu host \
-enable-kvm \
-nographic
```console
$ ./run-qemu-aarch64.sh
1: Set IPv4 address 172.44.0.2 mask 255.255.255.0 gw 172.44.0.1
en1: Added
en1: Interface is up
Powered by
o. .o _ _ __ _
Oo Oo ___ (_) | __ __ __ _ ' _) :_
oO oO ' _ `| | |/ / _)' _` | |_| _)
oOo oOO| | | | | (| | | (_) | _) :_
OoOoO ._, ._:_:_,\_._, .__,_:_, \___)
Atlas 0.13.1~5eb820bd
```

Open another console and use the `wget` command, similar to the QEMU x86_64 run above:

```console
$ wget 172.44.0.2
--2023-07-01 14:32:26-- http://172.44.0.2/
Connecting to 172.44.0.2:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 180 [text/html]
Saving to: ‘index.html’

index.html 100%[================================================================================================>] 180 --.-KB/s in 0s

2023-07-01 14:32:26 (9.87 MB/s) - ‘index.html’ saved [180/180]
```

For more information about `kraft` type ```kraft -h``` or read the
[documentation](http://docs.unikraft.org).
Similarly, to close the QEMU Nginx server, use the `Ctrl+a x` keyboard shortcut.
Loading

0 comments on commit d69f1ab

Please sign in to comment.