Getting Started on APPUiO Cloud with the Terminal using C
This tutorial explains how to run applications written in the C programming language on APPUiO Cloud using the command line.
If you aren’t familiar with issuing commands on a terminal session, you might want to try the Getting Started with C on the OpenShift Web Console guide instead.
Requirements
To follow this guide, please make sure that you have the following tools installed:
oc
-
You can download the OpenShift command directly from APPUiO Cloud, selecting the help menu (marked as a question mark) and selecting the "Command line tools" entry.
docker
orpodman
-
You can download them from www.docker.com and podman.io.
curl
-
Available from curl.se.
About the Application
To demo how to run applications written in the C programming language on APPUiO Cloud, we will use a small demo application using the GNU libmicrohttpd library, bundled as a container thanks to its corresponding Dockerfile
, and ready to be used on APPUiO Cloud.
You can browse the full source code of this application on GitLab.
The "Fortune in C" application does a few simple things:
-
When invoked on the browser, it returns a random number and a funny quote.
-
When invoked with an HTTP request including the
Accept: application/json
header, it returns the same information in JSON format. -
Finally, when invoked with an HTTP request including the
Accept: text/plain
header, it returns the same information in plain text format.
Learn more about the fortune-c
application, including how to edit and build it, on the project README.
The Application Router
The code below shows the main router of the application in the C programming language, located at src/main.c, courtesy of the GNU libmicrohttpd library.
int handler(void *cls, struct MHD_Connection *connection,
const char *url,
const char *method, const char *version,
const char *upload_data,
size_t *upload_data_size, void **con_cls)
{
char fortune[100000] = { "" };
int result = execute_command(fortune, "fortune");
char hostname[100] = { "" };
result = execute_command(hostname, "hostname");
int random = rand() % 1000;
char page[200000] = { "" };
const char *accept_header = MHD_lookup_connection_value (connection, MHD_HEADER_KIND, "Accept");
if (strcmp(accept_header, "application/json") == 0) {
result = respond_json(page, fortune, hostname, random);
}
else if (strcmp(accept_header, "text/plain") == 0) {
result = respond_text(page, fortune, random);
}
else {
result = respond_html(page, fortune, hostname, random);
}
struct MHD_Response *response;
int ret;
response = MHD_create_response_from_buffer(strlen(page),
(void *)page, MHD_RESPMEM_PERSISTENT);
ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
MHD_destroy_response(response);
return ret;
}
Run the Container
This step is optional; you can easily test the application locally with Docker:
docker run --rm --publish 8080:8080 registry.gitlab.com/vshn/applications/fortune-c:latest
Or with Podman:
podman run --rm --publish 8080:8080 registry.gitlab.com/vshn/applications/fortune-c:latest
Now you can test the application with curl
, for example to get some JSON:
curl http://localhost:8080 --header "Accept: application/json"
Or to see a plain text version:
curl http://localhost:8080 --header "Accept: text/plain"
You can also open a browser and navigate to localhost:8080 to get your fortune cookie of the day.
Dockerfile
The application includes a Dockerfile ready to build a container fully compatible with OpenShift. The snippet below shows the instructions used to build the actual running image:
# Step 2: Production image
FROM busybox:glibc
COPY --from=builder /builder/build/c-fortune /usr/local/bin/c-fortune
COPY --from=builder /usr/local/lib/libjson-c.so.5 /usr/local/lib/libjson-c.so.5
COPY --from=builder /usr/games/fortune /usr/local/bin/fortune
COPY --from=builder /usr/share/games/fortunes /usr/share/games/fortunes
COPY --from=builder /usr/lib/x86_64-linux-gnu/libmicrohttpd.so.12 /usr/lib/x86_64-linux-gnu/libmicrohttpd.so.12
COPY --from=builder /usr/lib/x86_64-linux-gnu/libgnutls.so.30 /usr/lib/x86_64-linux-gnu/libgnutls.so.30
COPY --from=builder /usr/lib/x86_64-linux-gnu/libp11-kit.so.0 /usr/lib/x86_64-linux-gnu/libp11-kit.so.0
COPY --from=builder /usr/lib/x86_64-linux-gnu/libidn2.so.0 /usr/lib/x86_64-linux-gnu/libidn2.so.0
COPY --from=builder /usr/lib/x86_64-linux-gnu/libunistring.so.2 /usr/lib/x86_64-linux-gnu/libunistring.so.2
COPY --from=builder /usr/lib/x86_64-linux-gnu/libtasn1.so.6 /usr/lib/x86_64-linux-gnu/libtasn1.so.6
COPY --from=builder /usr/lib/x86_64-linux-gnu/libnettle.so.8 /usr/lib/x86_64-linux-gnu/libnettle.so.8
COPY --from=builder /usr/lib/x86_64-linux-gnu/libhogweed.so.6 /usr/lib/x86_64-linux-gnu/libhogweed.so.6
COPY --from=builder /usr/lib/x86_64-linux-gnu/libgmp.so.10 /usr/lib/x86_64-linux-gnu/libgmp.so.10
COPY --from=builder /usr/lib/x86_64-linux-gnu/libffi.so.7 /usr/lib/x86_64-linux-gnu/libffi.so.7
COPY --from=builder /usr/lib/x86_64-linux-gnu/librecode.so.0 /usr/lib/x86_64-linux-gnu/librecode.so.0
COPY --from=builder /lib/x86_64-linux-gnu/libdl.so.2 /lib/x86_64-linux-gnu/libdl.so.2
EXPOSE 8080
(1)
USER 1001:0
CMD ["/usr/local/bin/c-fortune"]
1 | This explicitly prevents the container from running as root; this is a requirement of OpenShift, and a good practice for images in general. |
You can use the Dockerfile
above to build your own copy of the container, which you can then push to the registry of your choice. Clone the repo:
git clone https://gitlab.com/vshn/applications/fortune-c.git
cd
into it:
cd fortune-c
And build your image with Docker:
docker build -t fortune-c .
Or with Podman instead:
podman build -t fortune-c .
Step 1: Create a Project
Follow these steps to login to APPUiO Cloud on your terminal:
-
Login to the APPUiO Cloud console:
oc login --server=https://api.${zone}.appuio.cloud:6443
You can find the exact URL of your chosen zone in the APPUiO Cloud Portal.
This command displays a URL on your terminal:
You must obtain an API token by visiting https://oauth-openshift.apps.${zone}.appuio.cloud/oauth/token/request
-
Click on the link above and open it in your browser.
-
Click "Display token" and copy the login command shown as "Log in with this token"
-
Paste the
oc login
command on the terminal:oc login --token=sha256~_xxxxxx_xxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxxx-X \ --server=https://api.${zone}.appuio.cloud:6443
-
Create a new project called "[YOUR_USERNAME]-fortune-c"
oc new-project [YOUR_USERNAME]-fortune-c
-
To deploy the application we will use a standard Kubernetes
Deployment
object. Save the following YAML in a file calleddeployment.yaml
:apiVersion: apps/v1 kind: Deployment metadata: name: fortune-c spec: template: spec: containers: - image: registry.gitlab.com/vshn/applications/fortune-c:latest imagePullPolicy: Always name: fortune-container ports: - containerPort: 8080 metadata: labels: app: fortune-c selector: matchLabels: app: fortune-c strategy: type: Recreate --- apiVersion: v1 kind: Service metadata: name: fortune-c spec: ports: - port: 8080 targetPort: 8080 selector: app: fortune-c type: ClusterIP
-
Then apply the deployment to your APPUiO Cloud project:
oc apply -f deployment.yaml
And wait until your pod appears with the status "Running":
oc get pods --watch
Step 2: Publish your Application
At the moment your container is running but it’s not available from the Internet. To be able to access our application, we must create an Ingress
object.
-
Create another file called
ingress.yaml
with the following contents, customizing the parts marked as[YOUR_USERNAME]
and[YOUR_CHOSEN_ZONE]
to your liking (and according to the Zones documentation page):apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: cert-manager.io/cluster-issuer: letsencrypt-production name: fortune-c-ingress spec: rules: - host: [YOUR_USERNAME]-fortune-c.apps.[YOUR_CHOSEN_ZONE].appuio.cloud (1) http: paths: - pathType: Prefix path: / backend: service: name: fortune-c port: number: 8080 tls: - hosts: - [YOUR_USERNAME]-fortune-c.apps.[YOUR_CHOSEN_ZONE].appuio.cloud secretName: fortune-c-cert
1 Replace the placeholders YOUR_USERNAME
andYOUR_CHOSEN_ZONE
with valid values.
About URL lengths
Make sure that the total length of the prefix string
If your Ingress doesn’t generate a route after deploying your application, shorten the URL in your YAML and redeploy. |
-
Apply the ingress object to your APPUiO Cloud project and wait until you route shows as available.
oc apply -f ingress.yaml
And wait for your route to be ready:
oc get routes --watch
-
After a few seconds, you should be able to get your daily fortune message using
curl
in plain text!curl https://[YOUR_USERNAME]-fortune-c.apps.[YOUR_CHOSEN_ZONE].appuio.cloud --header "Accept: text/plain"
Or in JSON instead:
curl https://[YOUR_USERNAME]-fortune-c.apps.[YOUR_CHOSEN_ZONE].appuio.cloud --header "Accept: application/json"
Step 3: There’s no Step 3!
The "Fortune in C" application is now running on APPUiO Cloud. Congratulations! Hit the R key in your keyboard to see a new fortune message, or just wait 10 seconds to get a new one automatically.
What’s next? To run your own application written in C or using the GNU libmicrohttpd library on APPUiO Cloud, follow these steps:
-
Containerize the application making sure it’s compatible with APPUiO Cloud. The
Dockerfile
above can serve as a starting point. -
Enhance the deployment for your application with liveness and health probes, or better yet, create a Helm chart.
-
Configure your CI/CD system to automatically deploy your application to your preferred APPUiO Cloud zone.
Finally, when you’re done testing the fortune application, delete the fortune-c
project with the following command:
oc delete project [YOUR_USERNAME]-fortune-c