How to Deploy UniHTML on Kubernetes: A Step-by-Step Guide
Kubernetes has become the go-to platform for deploying scalable applications, and if you’re dealing with HTML-to-PDF conversion through UniHTML, you’re in for a smooth ride. In this guide, we’ll walk through the process of deploying UniHTML on a Kubernetes Talos cluster. By the end, you’ll have UniHTML up and running, converting HTML pages to PDF via an API.
What is UniHTML?
UniHTML is part of the UniDoc toolkit, a powerful tool for manipulating PDF files with Golang. While UniPDF handles PDF files, it doesn’t natively support HTML. That’s where UniHTML comes in, acting as a bridge to convert HTML into a format that UniDoc can process.
By deploying UniHTML on Kubernetes, you gain the ability to manage and scale the service in both public and private cloud environments. This approach ensures fast, reliable, and scalable document conversions with low latency across your network.
Prerequisites
Before we dive in, here’s what you need:
- A Kubernetes Talos cluster with multiple control planes and worker nodes.
- Flux to manage manifests.
- Cloudflared with Zero Trust for the ingress controller. This is already set up and working in our case, so we won’t cover it here.
We’ll use a hypothetical domain unihtml.command.is
to illustrate how this deployment works. Let’s get started!
Deployment Manifests for UniHTML
The deployment process for UniHTML in Kubernetes involves several configuration files. These files, or “manifests,” will help Kubernetes understand how to deploy, scale, and manage the service.
Let’s break down the key files you need.
1. kustomization.yaml
This is the main file that coordinates all the resources we’re about to configure. It tells Kustomize what to include in the deployment.
apiVersion:
kustomize.config.k8s.io/v1beta1kind:
Kustomizationresources:
- namespace.yaml
- deployment.yaml
- service.yaml
- ingress.yaml
- serviceaccount.yaml
- secret.sops.yaml
2. namespace.yaml
Namespaces in Kubernetes allow you to group and isolate resources. This file creates a dedicated namespace for UniHTML to keep it self-contained and easier to manage.
apiVersion:
v1kind:
Namespacemetadata:
name: unihtml
3. serviceaccount.yaml
A service account restricts the permissions that UniHTML has in your cluster. This ensures that UniHTML only gets access to the resources it needs.
apiVersion:
v1kind:
ServiceAccountmetadata:
name:
unihtmlnamespace: unihtml
4. deployment.yaml
This is the heart of the deployment, defining how many replicas of UniHTML to run, the container image to use, and how to handle the API that listens on port 8080.
The secret to running this? Licensing. You’ll need to mount a license file in the container to activate UniHTML. We store this license in a Kubernetes secret and mount it as read-only.
apiVersion: apps/v1
kind: Deployment
metadata:
name: unihtml-server
namespace: unihtml
spec:
replicas: 1
selector:
matchLabels:
app: unihtml
template:
metadata:
labels:
app: unihtml
spec:
volumes:
- name: secret-volume
secret:
secretName: unihtml
serviceAccountName: unihtml
containers:
- name: unihtml-server
image: unidoccloud/unihtml:202408
volumeMounts:
- name: secret-volume
mountPath: /etc/secret-volume
readOnly: true
env:
- name: UNIHTML_LICENSE_PATH
value: /etc/secret-volume/license_file
- name: UNIHTML_CUSTOMER_NAME
valueFrom:
secretKeyRef:
name: unihtml
key: customer_name
ports:
- containerPort: 8080
Security Note: Chromium, which UniHTML uses for rendering, requires the container to run as root. It’s not ideal, but this is a Chromium limitation for now.
5. secret.sops.yaml
Secrets should never be stored as plain text in your repository. We’re using SOPS to encrypt this file, which contains the customer_name
and the license content.
apiVersion: v1
kind: Secret
metadata:
name: unihtml
namespace: unihtml
data:
customer_name: <base64-encoded-customer-name>
license_file: <base64-encoded-license-file>
6. service.yaml
This file exposes the UniHTML service on port 8080 inside the cluster. We’ll pair this with an Ingress to make it accessible to the public.
apiVersion: v1
kind: Service
metadata:
name: unihtml-server-service
namespace: unihtml
spec:
selector:
app: unihtml
ports:
- protocol: TCP
port: 8080
targetPort: 8080
7. ingress.yaml
Ingress allows you to expose your service to the internet.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: command-ingress-unihtml
namespace: unihtml
annotations:
nginx.org/mergeable-ingress-type: 'minion'
spec:
ingressClassName: nginx
rules:
- host: unihtml.command.is
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: unihtml-server-service
port:
number: 8080
If you’re looking for additional configurations or insights, this guide offers another helpful perspective on deploying UniHTML.
Converting HTML to PDF
With the service deployed, we can now convert HTML to PDF using UniHTML’s API. Below is a simple client program in Go that takes a webpage (in this case, https://command.is) and converts it to PDF.
package main
import (
"context"
"fmt"
"os"
"time"
"github.com/unidoc/unihtml"
"github.com/unidoc/unihtml/sizes"
"github.com/unidoc/unipdf/v3/common/license"
"github.com/unidoc/unipdf/v3/creator"
)
const offlineLicenseKey = `
-----BEGIN UNIDOC LICENSE KEY-----
YOUR-LICENSE-KEY-HERE
-----END UNIDOC LICENSE KEY-----
`
func init() {
customerName := `Command`
err := license.SetLicenseKey(offlineLicenseKey, customerName)
if err != nil {
panic(err)
}
}
func main() {
if len(os.Args) != 2 {
fmt.Println("Err: No UniHTML server path provided")
os.Exit(1)
}
err := unihtml.Connect(os.Args[1])
if err != nil {
fmt.Printf("Err: Connect failed: %v\n", err)
os.Exit(1)
}
c := creator.New()
webDocument, err := unihtml.NewDocument("https://command.is")
if err != nil {
fmt.Printf("Err: NewDocument failed: %v\n", err)
os.Exit(1)
}
webDocument.SetPageSize(sizes.A3)
webDocument.SetMargins(30, 30, 30, 30)
webDocument.SetLandscapeOrientation()
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
pages, err := webDocument.GetPdfPages(ctx)
for _, p := range pages {
if err := c.AddPage(p); err != nil {
fmt.Printf("Err: Adding page failed: %v\n", err)
os.Exit(1)
}
}
err = c.WriteToFile("weburl.pdf")
if err != nil {
fmt.Printf("Err: %v\n", err)
os.Exit(1)
}
}
Compile and Run
To convert your HTML page, compile and run the program:
go build -o unihtml-convert main.go
./unihtml-convert https://unihtml.command.is:443
This generates weburl.pdf
, a PDF version of https://command.is. Voilà!
Conclusion
Deploying UniHTML on a Kubernetes Talos cluster is a straightforward process with the right tools. Once you’ve set up your manifests and deployed using Flux, you can scale, update, and manage your deployment with ease.
The ability to convert HTML to PDF with an API gives you flexibility and control over document generation. Whether you’re handling complex web content or simple HTML pages, UniHTML on Kubernetes gets the job done efficiently.
So, what are you waiting for? Start converting, and watch your PDFs roll in like magic!