ANSI C in OpenWhisk
Führen Sie nativen C-Code als Serverless-Funktion mit einer benutzerdefinierten Docker-Runtime auf evrtng functions aus. Maximale Performance, null Server zu verwalten.
Warum ANSI C?
OpenWhisk liefert von Haus aus keine ANSI C-Runtime — aber die Docker-Action-Unterstützung bedeutet, dass Sie jedes kompilierte C-Binary als Serverless-Funktion ausführen können. Dieser Ansatz bietet Ihnen:
// Voraussetzungen
GCC
GCC-Compiler für lokale Tests (optional)
$ wsk --version wsk 1.2.0 $ docker --version Docker version 25.0.0 $ gcc --version gcc (Ubuntu 11.4.0) 11.4.0
Schritt-für-Schritt-Anleitung
Schreiben Sie Ihre C-Funktion
OpenWhisk kommuniziert mit Ihrer Funktion via stdin/stdout über ein einfaches JSON-Protokoll. Ihr C-Programm liest einen JSON-String von stdin und schreibt einen JSON-String nach stdout.
/* * evrtng functions – ANSI C action example * Reads JSON from argv[1] (OpenWhisk passes params as arg), * prints a JSON result to stdout. */ #include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char *argv[]) { /* Log to stderr – shows up in wsk activation logs */ fprintf(stderr, "[evrtng] ANSI C action invoked\n"); /* Safely read the name param from argv[1] */ const char *args = (argc > 1) ? argv[1] : "undefined"; /* Print structured JSON result to stdout */ printf( "{ \"msg\": \"Hello from ANSI C!\", \"args\": \"%s\" }\n", args ); return 0; }
# Compile $ gcc -o example example.c # Test with a mock argument $ ./example '{"name":"evrtng"}' { "msg": "Hello from ANSI C!", "args": "{\"name\":\"evrtng\"}" }
Dockerfile erstellen
Verpacken Sie das kompilierte Binary in einem minimalen Docker-Image. Wir kompilieren innerhalb des Containers, um sicherzustellen, dass das Binary zur Runtime-Architektur passt.
# Stage 1 – Build FROM ubuntu:22.04 AS builder RUN apt-get update && \ apt-get install -y gcc libc-dev && \ rm -rf /var/lib/apt/lists/* WORKDIR /build COPY example.c . # Compile with optimisations and static linking RUN gcc -O2 -static -o example example.c # Stage 2 – Runtime (minimal scratch image) FROM ubuntu:22.04 RUN apt-get update && \ apt-get install -y libc6 && \ rm -rf /var/lib/apt/lists/* COPY --from=builder /build/example /usr/local/bin/example # OpenWhisk calls this entrypoint ENTRYPOINT ["/usr/local/bin/example"]
Der Multi-Stage-Build hält das finale Image klein. Die Verwendung von -static für das C-Binary macht es vollständig selbstenthalten, sogar auf einem minimalen Base-Image.
Docker-Image builden & pushen
Builden Sie das Image lokal und pushen Sie es in eine Registry, auf die evrtng functions zugreifen kann. Ersetzen Sie YOUR_DOCKERHUB_USER durch Ihren Docker Hub-Benutzernamen.
# Build the image $ docker build -t YOUR_DOCKERHUB_USER/openwhisk-ansi-c . Step 1/8 : FROM ubuntu:22.04 AS builder ... Successfully built a1b2c3d4e5f6 Successfully tagged yourusername/openwhisk-ansi-c:latest # Log in to Docker Hub $ docker login # Push the image $ docker push YOUR_DOCKERHUB_USER/openwhisk-ansi-c The push refers to repository [docker.io/yourusername/openwhisk-ansi-c] latest: digest: sha256:abc123... size: 27.4 MB # Verify the image is accessible $ docker pull YOUR_DOCKERHUB_USER/openwhisk-ansi-c
Action in OpenWhisk registrieren
Erstellen Sie die Action mit dem Flag --docker und verweisen Sie auf Ihr gepushtes Image. Das Flag --web true macht sie per HTTP zugänglich.
# Create the action with your Docker image $ wsk action create ansiCAction \ --docker YOUR_DOCKERHUB_USER/openwhisk-ansi-c \ --web true ok: created action ansiCAction # Verify it was registered $ wsk action list | grep ansiCAction /guest/default/ansiCAction private blackbox # Get the public web URL $ wsk action get ansiCAction --url https://fnc.evrtng.cloud/api/v1/web/guest/default/ansiCAction
Aufrufen & Überwachen
Testen Sie Ihre C-Funktion über die wsk CLI oder über HTTP. Prüfen Sie Logs, um die stderr-Ausgabe Ihres C-Programms zu sehen.
# Blocking invocation with params $ wsk action invoke ansiCAction \ --result \ --param args "test-input" { "msg": "Hello from ANSI C!", "args": "test-input" } # Async invocation $ wsk action invoke ansiCAction --param args "async-test" ok: invoked /guest/default/ansiCAction with id a1b2c3d4... # View the logs (stderr output from your C program) $ wsk activation logs a1b2c3d4 2025-01-01T12:00:00.000Z stderr: [evrtng] ANSI C action invoked
# POST via curl $ curl -X POST \ https://fnc.evrtng.cloud/api/v1/web/guest/default/ansiCAction \ -H "Content-Type: application/json" \ -d '{"args": "curl-test"}' { "msg": "Hello from ANSI C!", "args": "curl-test" } # GET with query param $ curl "https://fnc.evrtng.cloud/api/v1/web/guest/default/ansiCAction?args=hello" { "msg": "Hello from ANSI C!", "args": "hello" }
JSON mit cJSON parsen
Für den realen Einsatz möchten Sie die JSON-Parameter parsen, die OpenWhisk übergibt. Hier ist ein vollständigeres Beispiel mit der schlanken cJSON-Bibliothek.
action_json.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include "cJSON.h" /* cJSON: MIT License */ int main(int argc, char *argv[]) { /* OpenWhisk passes JSON as first CLI argument */ if (argc < 2) { printf("{\"error\":\"no params\"}\n"); return 1; } /* Parse input JSON */ cJSON *input = cJSON_Parse(argv[1]); if (!input) { printf("{\"error\":\"invalid JSON\"}\n"); return 1; } /* Extract "name" field */ cJSON *name_item = cJSON_GetObjectItem(input, "name"); const char *name = (name_item && cJSON_IsString(name_item)) ? name_item->valuestring : "World"; /* Build and output the response */ cJSON *output = cJSON_CreateObject(); cJSON_AddStringToObject(output, "message", strcat(strcpy(malloc(64), "Hello, "), name)); cJSON_AddStringToObject(output, "runtime", "ANSI C"); printf("%s\n", cJSON_Print(output)); cJSON_Delete(input); cJSON_Delete(output); return 0; }
Dockerfile mit cJSON
FROM ubuntu:22.04 AS builder RUN apt-get update && apt-get install -y \ gcc libc-dev wget && \ rm -rf /var/lib/apt/lists/* # Download cJSON (MIT license) RUN wget -q \ https://raw.githubusercontent.com/DaveGamble/cJSON/master/cJSON.c \ https://raw.githubusercontent.com/DaveGamble/cJSON/master/cJSON.h WORKDIR /build COPY action_json.c cJSON.c cJSON.h . # Compile with cJSON RUN gcc -O2 -o action action_json.c cJSON.c -lm FROM ubuntu:22.04 RUN apt-get update && apt-get install -y libc6 && \ rm -rf /var/lib/apt/lists/* COPY --from=builder /build/action /usr/local/bin/action ENTRYPOINT ["/usr/local/bin/action"]
$ docker build -t YOU/ow-c-json . $ docker push YOU/ow-c-json $ wsk action create cJsonAction \ --docker YOU/ow-c-json \ --web true $ wsk action invoke cJsonAction \ --result \ --param name "evrtng" { "message": "Hello, evrtng", "runtime": "ANSI C" }
Verwaltung Ihrer C-Action
# Update after rebuilding the Docker image $ wsk action update ansiCAction \ --docker YOU/openwhisk-ansi-c # Set memory limit (e.g. 256 MB for C processing) $ wsk action update ansiCAction \ --docker YOU/openwhisk-ansi-c \ --memory 256 # Set a timeout (e.g. 30 seconds) $ wsk action update ansiCAction \ --docker YOU/openwhisk-ansi-c \ --timeout 30000 # View action details $ wsk action get ansiCAction # Use in a sequence with other actions $ wsk action create myPipeline \ --sequence ansiCAction,anotherAction # Delete the action $ wsk action delete ansiCAction ok: deleted action ansiCAction
Implementierungshinweise
01
OpenWhisk übergibt Parameter als JSON-String in argv[1], nicht via stdin. Ihr C-Programm muss argv[1] auslesen.
02
Der Output muss gültiges JSON auf stdout sein. Alles auf stderr erscheint in den Aktivierungs-Logs (für Debugging verwenden).
03
Das Docker-Image muss öffentlich zugänglich sein oder in einer Registry gehostet werden, die mit evrtng functions konfiguriert ist.
04
Kompilieren Sie aus Sicherheitsgründen mit -fstack-protector-strong und validieren Sie alle Eingaben vor der Verwendung.
05
Wenn Sie Shared Libraries (openssl, curl etc.) benötigen, linken Sie diese statisch oder installieren Sie sie im Docker-Image.
06
cJSON (MIT-Lizenz) ist eine sichere Wahl für die JSON-Verarbeitung in C. libjansson und yyjson sind ebenfalls gute Alternativen.
