Ingress tutorials

Load balance FastCGI applications

Implementing FastCGI with HAProxy Kubernetes Ingress Controller Jump to heading

This tutorial will walk you through configuring the HAProxy Kubernetes Ingress Controller to enable direct communication using the FastCGI protocol with PHP-FPM applications deployed in Kubernetes. You will also deploy and configure a test application to demonstrate how HAProxy can integrate with PHP applications by routing requests to the appropriate PHP test programs acting as backend microservices.

HAProxy supports the FastCGI protocol. When you use a web server, such as Apache, that can translate HTTP requests to FastCGI requests, you can instead use HAProxy. You can configure HAProxy to handle routing and translating requests to PHP applications. There is no need for additional web servers, therefore removing unnecessary hops. Although the HAProxy Kubernetes Ingress Controller doesn’t natively support FastCGI, you can enable the underlying HAProxy load balancer to use FastCGI by incorporating custom configurations. There are plans for the HAProxy Kubernetes Ingress Controller to support the protocol natively in the future.

Configure the HAProxy Kubernetes Ingress Controller for FastCGI Jump to heading

To configure the HAProxy Kubernetes Ingress Controller for the demo application, you must declare an fcgi-app in your HAProxy configuration, along with a few PHP-related configuration directives, and you must also declare Ingress definitions for the PHP microservices. The following steps show how to use an auxiliary HAProxy configuration in combination with an Ingress definition to define and configure the ingress controller for FastCGI.

Create the ConfigMap for the auxiliary configuration Jump to heading

To enable communication between the ingress controller and FastCGI applications, you must add additional directives to your HAProxy configuration. While you can’t add this configuration block using an Ingress resource annotation, you can instead use an auxiliary config file. The ingress controller manages the main HAProxy configuration, and editing or adding to the configuration requires an auxiliary configuration file. To make the ingress controller and its underlying load balancer aware of this auxiliary config, create this file in the container using a ConfigMap.

To create the ConfigMap in your cluster:

  1. Create a file named haproxy-aux.yaml and add the following to it:

    haproxy-aux.yaml
    yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
    name: haproxy-auxiliary-configmap
    namespace: haproxy-controller
    data:
    haproxy-auxiliary.cfg: |
    fcgi-app php-fpm
    log-stderr global
    docroot /var/www/html
    path-info ^(/.+\.php)(/.*)?$
    haproxy-aux.yaml
    yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
    name: haproxy-auxiliary-configmap
    namespace: haproxy-controller
    data:
    haproxy-auxiliary.cfg: |
    fcgi-app php-fpm
    log-stderr global
    docroot /var/www/html
    path-info ^(/.+\.php)(/.*)?$

    This will create a file in the ingress controller’s container named haproxy-auxiliary.cfg. Here, you are specifying the following:

    • An fcgi-app named php-fpm.
    • Log STDERR messages received by the FastCGI application.
    • The docroot, the location of the PHP scripts on the PHP-FPM pods, is located at /var/www/html. In subsequent steps for the test application, the PHP-FPM image you will use expects scripts to be located in this directory.
    • A regular expression for extracting the name of the appropriate script from the URL with path-info.

    When HAProxy starts, it will load these additional configuration directives from the file.

  2. Apply the ConfigMap. You should create it in the haproxy-controller namespace. The HAProxy Ingress Controller should also be deployed in this namespace.

    nix
    kubectl apply -f haproxy-aux.yaml -n haproxy-controller
    nix
    kubectl apply -f haproxy-aux.yaml -n haproxy-controller
    output
    text
    configmap/haproxy-aux created
    output
    text
    configmap/haproxy-aux created

Next, you will mount the data from the haproxy-aux.yaml file into the container as /usr/local/etc/haproxy/haproxy-aux.cfg.

Mount the ConfigMap in the ingress controller container Jump to heading

Once the ConfigMap exists within your cluster, you must mount it as a file in the container. Mounting the file at /usr/local/etc/haproxy/haproxy-aux.cfg will make the HAProxy Ingress Controller inject the contents of the file into its main configuration. When the ingress controller is installed with Helm, you can mount this file using the extraVolumes and extraVolumeMounts properties of the Helm values file.

To mount the auxiliary configuration file:

  1. Create a file named values.yaml and add the following to it:

    values.yaml
    yaml
    controller:
    volumeMounts:
    - name: haproxy-auxiliary-volume
    configMap:
    name: haproxy-auxiliary-configmap
    extraVolumeMounts:
    - name: haproxy-auxiliary-volume
    mountPath: /usr/local/etc/haproxy/haproxy-aux.cfg
    subPath: haproxy-auxiliary.cfg
    values.yaml
    yaml
    controller:
    volumeMounts:
    - name: haproxy-auxiliary-volume
    configMap:
    name: haproxy-auxiliary-configmap
    extraVolumeMounts:
    - name: haproxy-auxiliary-volume
    mountPath: /usr/local/etc/haproxy/haproxy-aux.cfg
    subPath: haproxy-auxiliary.cfg
  2. Perform a Helm upgrade using the values file. This will reconfigure the ingress controller with the properties specified in the values file:

    nix
    helm upgrade -f values.yaml haproxy-kubernetes-ingress haproxytech/kubernetes-ingress \
    --create-namespace \
    --namespace haproxy-controller
    nix
    helm upgrade -f values.yaml haproxy-kubernetes-ingress haproxytech/kubernetes-ingress \
    --create-namespace \
    --namespace haproxy-controller
    output
    text
    NAME: haproxy-kubernetes-ingress
    LAST DEPLOYED: Wed Jul 24 19:27:16 2024
    NAMESPACE: haproxy-controller
    STATUS: deployed
    [...]
    output
    text
    NAME: haproxy-kubernetes-ingress
    LAST DEPLOYED: Wed Jul 24 19:27:16 2024
    NAMESPACE: haproxy-controller
    STATUS: deployed
    [...]

The HAProxy Kubernetes Ingress Controller is now deployed and is aware of its auxiliary configuration. You can see this in the ingress controller logs using the kubectl logs command with the name of the haproxy-kubernetes-ingress pod:

nix
kubectl logs haproxy-kubernetes-ingress-7bc4f66d5c-5c8rt -n haproxy-controller
nix
kubectl logs haproxy-kubernetes-ingress-7bc4f66d5c-5c8rt -n haproxy-controller
output
text
2024/07/26 20:23:24 INFO controller/monitor.go:118 restart required : auxiliary configuration file created
2024/07/26 20:23:24 INFO controller/monitor.go:122 Auxiliary HAProxy config '/etc/haproxy/haproxy-aux.cfg' updated
output
text
2024/07/26 20:23:24 INFO controller/monitor.go:118 restart required : auxiliary configuration file created
2024/07/26 20:23:24 INFO controller/monitor.go:122 Auxiliary HAProxy config '/etc/haproxy/haproxy-aux.cfg' updated

Tip

You can find the name of your haproxy-kubernetes-ingress pods using the command kubectl get pods -n haproxy-controller.

Create ingress definitions for the test PHP microservices Jump to heading

To route HTTP requests to the Services for the PHP microservices, you must add an Ingress definition.

Info

You will create the Services for the PHP microservices in subsequent steps.

To create the Ingress definition:

  1. Create a file named ingress.yaml and add the following to it:

    ingress.yaml
    yaml
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
    name: myapp-ingress
    annotations:
    haproxy.org/path-rewrite: (\/plants\/|\/grocery\/)(.*) /\2
    spec:
    ingressClassName: haproxy
    rules:
    - host: "yourdomain.com"
    http:
    paths:
    - path: /grocery/
    pathType: Prefix
    backend:
    service:
    name: grocery-service
    port:
    number: 9000
    - path: /plants/
    pathType: Prefix
    backend:
    service:
    name: plants-service
    port:
    number: 9000
    ingress.yaml
    yaml
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
    name: myapp-ingress
    annotations:
    haproxy.org/path-rewrite: (\/plants\/|\/grocery\/)(.*) /\2
    spec:
    ingressClassName: haproxy
    rules:
    - host: "yourdomain.com"
    http:
    paths:
    - path: /grocery/
    pathType: Prefix
    backend:
    service:
    name: grocery-service
    port:
    number: 9000
    - path: /plants/
    pathType: Prefix
    backend:
    service:
    name: plants-service
    port:
    number: 9000

    Here, you define the following:

    • An Ingress resource in the default namespace named myapp-ingress.
    • The host as yourdomain.com for this demo application. Be sure to replace this with the domain name for your application!
    • Requests to this host will be routed to the appropriate Service on port 9000 based on the URL path. In this example, there are two Services: grocery-service and plants-service. You will define and create these Services in subsequent steps.
    • A path-rewrite annotation that will strip away part of the URL before sending the requests to the Services. Your PHP microservices will expect to receive a URL with the name of the PHP file only, and these annotations accomplish this, effectively turning /grocery/grocery.php into just grocery.php, for example.
  2. Create the Ingress resource using kubectl apply.

    nix
    kubectl apply -f ingress.yaml
    nix
    kubectl apply -f ingress.yaml
    output
    text
    ingress.networking.k8s.io/example-ingress created
    output
    text
    ingress.networking.k8s.io/example-ingress created

    Create this in the default namespace, as this is where you will deploy the application Services and Deployments.

This configures the ingress controller for FastCGI. Next, you will create the Services for the PHP microservices and deploy a test application.

Deploy a test PHP FastCGI application Jump to heading

For your typical productionized application, you would create Kubernetes Deployments that would manage one or more pods (depending on the number of replicas) containing your application code and a FastCGI runtime. For this test example, you will deploy containers with php-fpm built in using the php:8-fpm image and mount .php code files into them at /www/var/html. This is the default location this image expects to find .php files. For the test application, you will deploy two containers, each acting as a separate microservice, to which the ingress controller will route requests based on paths.

If you have ready a containerized PHP application for your Kubernetes cluster, you could use it for testing in place of this demo application; just be sure that your auxiliary configuration you defined earlier includes the correct location for your PHP application. This is the docroot directive in the HAProxy auxiliary configuration. Also, per the configuration you deployed earlier, HAProxy expects your FastCGI application to be listening on port 9000. This port is configurable in your Service and Ingress settings.

To create the test PHP microservices, you will create ConfigMaps. These ConfigMaps will contain test code that you will then mount into the PHP-FPM containers at /www/var/html. The PHP-FPM process will be able to see these files and serve them upon request.

For testing only

Note that this method of deploying a PHP FastCGI application, that is, mounting PHP code via ConfigMaps, is for testing only and shouldn’t be used for production; its purpose is for simplicity, brevity, and ease of deployment within this tutorial. For your production deployment, you would have a containerized PHP application that includes your runtime and application code.

Also, the contents of the ConfigMap you will define are executable PHP code. As always, be sure to review any code and ensure that you are comfortable with executing it in your environment before you deploy. See the next steps for an explanation of this test code.

Create a ConfigMap to mount test PHP microservices code Jump to heading

To create the ConfigMap:

  1. Create a file named scripts.yaml and copy the following into it.

    scripts.yaml
    yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
    name: grocery-script
    data:
    grocery.php: |
    <?php
    $jsonData = array(
    'bananas' => 3,
    'bread' => 2,
    'bacon' => 1
    );
    header('Content-Type: application/json');
    echo json_encode($jsonData);
    ?>
    ---
    apiVersion: v1
    kind: ConfigMap
    metadata:
    name: plants-script
    data:
    plants.php: |
    <?php
    $jsonData = array(
    'tree' => 'oak',
    'flower' => 'rose',
    'vegetable' => 'carrot'
    );
    header('Content-Type: application/json');
    echo json_encode($jsonData);
    ?>
    scripts.yaml
    yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
    name: grocery-script
    data:
    grocery.php: |
    <?php
    $jsonData = array(
    'bananas' => 3,
    'bread' => 2,
    'bacon' => 1
    );
    header('Content-Type: application/json');
    echo json_encode($jsonData);
    ?>
    ---
    apiVersion: v1
    kind: ConfigMap
    metadata:
    name: plants-script
    data:
    plants.php: |
    <?php
    $jsonData = array(
    'tree' => 'oak',
    'flower' => 'rose',
    'vegetable' => 'carrot'
    );
    header('Content-Type: application/json');
    echo json_encode($jsonData);
    ?>

    This file has two ConfigMaps, each containing one PHP file. These PHP files are two scripts that execute PHP code and return results as JSON. The first script, grocery.php, will return a listing and quantity for a grocery shopping list. The second script, plants.php, will return a JSON mapping of some plants, perhaps a secondary shopping list. You will query for these files in subsequent steps to verify your configuration.

  2. Create the ConfigMap in the default namespace:

    nix
    kubectl apply -f scripts.yaml
    nix
    kubectl apply -f scripts.yaml
    output
    text
    configmap/grocery-script created
    configmap/plants-script created
    output
    text
    configmap/grocery-script created
    configmap/plants-script created

Create Deployments for the test PHP microservices Jump to heading

To create Deployments for the PHP microservices:

  1. Create a file named deployments.yaml and add the following to it:

    deployments.yaml
    yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: grocery-deployment
    labels:
    app: grocery
    spec:
    replicas: 1
    selector:
    matchLabels:
    app: grocery
    template:
    metadata:
    labels:
    app: grocery
    spec:
    containers:
    - name: grocery
    image: php:8-fpm
    volumeMounts:
    - name: grocery-script
    mountPath: /var/www/html
    volumes:
    - name: grocery-script
    configMap:
    name: grocery-script
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: plants-deployment
    labels:
    app: plants
    spec:
    replicas: 1
    selector:
    matchLabels:
    app: plants
    template:
    metadata:
    labels:
    app: plants
    spec:
    containers:
    - name: plants
    image: php:8-fpm
    volumeMounts:
    - name: plants-script
    mountPath: /var/www/html
    volumes:
    - name: plants-script
    configMap:
    name: plants-script
    deployments.yaml
    yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: grocery-deployment
    labels:
    app: grocery
    spec:
    replicas: 1
    selector:
    matchLabels:
    app: grocery
    template:
    metadata:
    labels:
    app: grocery
    spec:
    containers:
    - name: grocery
    image: php:8-fpm
    volumeMounts:
    - name: grocery-script
    mountPath: /var/www/html
    volumes:
    - name: grocery-script
    configMap:
    name: grocery-script
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: plants-deployment
    labels:
    app: plants
    spec:
    replicas: 1
    selector:
    matchLabels:
    app: plants
    template:
    metadata:
    labels:
    app: plants
    spec:
    containers:
    - name: plants
    image: php:8-fpm
    volumeMounts:
    - name: plants-script
    mountPath: /var/www/html
    volumes:
    - name: plants-script
    configMap:
    name: plants-script

    This defines:

    • A Deployment named grocery-deployment and a Deployment named plants-deployment will each run in their own containers that use the php:8-fpm image. This image, by default, expects .php files to reside at /var/www/html.
    • A volumeMount of the grocery-script volume, also defined in this file, to mount the contents of the grocery-script ConfigMap that you specified earlier into the container at /var/www/html in the grocery container. PHP-FPM will look for php files at this location. The same applies to the plants-script volume in the plants container.
  2. Create the Deployments in the default namespace:

    nix
    kubectl apply -f deployments.yaml
    nix
    kubectl apply -f deployments.yaml
    output
    text
    deployment.apps/grocery-deployment created
    deployment.apps/plants-deployment created
    output
    text
    deployment.apps/grocery-deployment created
    deployment.apps/plants-deployment created

Create Services for the PHP microservices Jump to heading

You need two services to communicate with the microservice pods. Though you didn’t define the Services in previous steps, you configured the ingress controller to communicate with the microservices through two Services on port 9000: grocery-service and plants-service. These two services correspond to the Deployments of the same names. You will now define and create these Services.

In order for the ingress controller to apply the appropriate configuration to the backends that will service the PHP microservices, you need to add the following annotation to each of the Service definitions:

yaml
haproxy.org/backend-config-snippet: |
default-server proto fcgi
use-fcgi-app php-fpm
yaml
haproxy.org/backend-config-snippet: |
default-server proto fcgi
use-fcgi-app php-fpm

This informs the ingress controller, which will in turn configure the load balancer, that the backends associated with these Services will use the fcgi-app you defined earlier in the HAProxy auxiliary configuration named php-fpm. The directive default-server proto fcgi will apply those options to all servers defined in the backends, thus enabling FastCGI communication between HAProxy and the PHP-FPM pods.

To create the Services:

  1. Create a file named services.yaml and add the following to it:

    services.yaml
    yaml
    apiVersion: v1
    kind: Service
    metadata:
    name: grocery-service
    annotations:
    haproxy.org/backend-config-snippet: |
    default-server proto fcgi
    use-fcgi-app php-fpm
    spec:
    selector:
    app: grocery
    ports:
    - protocol: TCP
    port: 9000
    ---
    apiVersion: v1
    kind: Service
    metadata:
    name: plants-service
    annotations:
    haproxy.org/backend-config-snippet: |
    default-server proto fcgi
    use-fcgi-app php-fpm
    spec:
    selector:
    app: plants
    ports:
    - protocol: TCP
    port: 9000
    services.yaml
    yaml
    apiVersion: v1
    kind: Service
    metadata:
    name: grocery-service
    annotations:
    haproxy.org/backend-config-snippet: |
    default-server proto fcgi
    use-fcgi-app php-fpm
    spec:
    selector:
    app: grocery
    ports:
    - protocol: TCP
    port: 9000
    ---
    apiVersion: v1
    kind: Service
    metadata:
    name: plants-service
    annotations:
    haproxy.org/backend-config-snippet: |
    default-server proto fcgi
    use-fcgi-app php-fpm
    spec:
    selector:
    app: plants
    ports:
    - protocol: TCP
    port: 9000

    This defines:

    • A Service named grocery-service will communicate with the grocery pods, that is, the pods labeled with app: grocery, at port 9000. The ingress controller will use this configuration to configure the backend and its list of servers to communicate with the PHP microservice at port 9000.
    • A Service named plants-service will communicate with the plants pods, that is, the pods labeled with app: plants, at port 9000. The ingress controller will use this configuration to configure the backend and its list of servers to communicate with the PHP microservice at port 9000.
  2. Create the Services in the default namespace:

    nix
    k apply -f services.yaml
    nix
    k apply -f services.yaml
    output
    text
    service/grocery-service created
    service/plants-service created
    output
    text
    service/grocery-service created
    service/plants-service created

Examine the ingress controller logs and configuration Jump to heading

The ingress controller monitors the Services named in the Ingress resource, and when the Services are created, the ingress controller will automatically configure the load balancer.

  1. To see in the logs that new backends were added to the configuration, use the kubectl logs command and provide the name of your haproxy-kubernetes-ingress pod:

    nix
    kubectl logs haproxy-kubernetes-ingress-7bc4f66d5c-s4rkc -n haproxy-controller
    nix
    kubectl logs haproxy-kubernetes-ingress-7bc4f66d5c-s4rkc -n haproxy-controller
    output
    text
    [...]
    2024/07/29 21:27:32 INFO service/service.go:164 [transactionID=9e91f547-e0b7-46e7-805b-b0ded84e5abc] reload required : Service 'default/grocery-service': new backend 'default_grocery-service_9000'
    2024/07/29 21:27:32 INFO service/endpoints.go:160 [transactionID=9e91f547-e0b7-46e7-805b-b0ded84e5abc] reload required : [CONFIG] [BACKEND] [SERVER] Server slots in backend 'default_grocery-service_9000' scaled to match available endpoints
    2024/07/29 21:27:32 INFO service/service.go:164 [transactionID=9e91f547-e0b7-46e7-805b-b0ded84e5abc] reload required : Service 'default/plants-service': new backend 'default_plants-service_9000'
    [...]
    output
    text
    [...]
    2024/07/29 21:27:32 INFO service/service.go:164 [transactionID=9e91f547-e0b7-46e7-805b-b0ded84e5abc] reload required : Service 'default/grocery-service': new backend 'default_grocery-service_9000'
    2024/07/29 21:27:32 INFO service/endpoints.go:160 [transactionID=9e91f547-e0b7-46e7-805b-b0ded84e5abc] reload required : [CONFIG] [BACKEND] [SERVER] Server slots in backend 'default_grocery-service_9000' scaled to match available endpoints
    2024/07/29 21:27:32 INFO service/service.go:164 [transactionID=9e91f547-e0b7-46e7-805b-b0ded84e5abc] reload required : Service 'default/plants-service': new backend 'default_plants-service_9000'
    [...]
  2. To view the load balancer configuration, use the following command and provide the name of your haproxy-kubernetes-ingress pod:

    nix
    kubectl exec -it haproxy-kubernetes-ingress-7bc4f66d5c-5c8rt -n haproxy-controller -- cat /etc/haproxy/haproxy.cfg
    nix
    kubectl exec -it haproxy-kubernetes-ingress-7bc4f66d5c-5c8rt -n haproxy-controller -- cat /etc/haproxy/haproxy.cfg
    /etc/haproxy/haproxy.cfg
    haproxy
    [...]
    backend default_grocery-service_9000
    mode http
    balance roundrobin
    option forwardfor
    no option abortonclose
    default-server check
    ###_config-snippet_### BEGIN
    ### service:default_grocery-service_9000/default/grocery-service ###
    default-server proto fcgi
    use-fcgi-app php-fpm
    ###_config-snippet_### END
    server SRV_1 100.44.0.2:9000 enabled
    [...]
    backend default_plants-service_9000
    mode http
    balance roundrobin
    option forwardfor
    no option abortonclose
    default-server check
    ###_config-snippet_### BEGIN
    ### service:default_plants-service_9000/default/plants-service ###
    default-server proto fcgi
    use-fcgi-app php-fpm
    ###_config-snippet_### END
    server SRV_1 100.36.0.1:9000 enabled
    [...]
    /etc/haproxy/haproxy.cfg
    haproxy
    [...]
    backend default_grocery-service_9000
    mode http
    balance roundrobin
    option forwardfor
    no option abortonclose
    default-server check
    ###_config-snippet_### BEGIN
    ### service:default_grocery-service_9000/default/grocery-service ###
    default-server proto fcgi
    use-fcgi-app php-fpm
    ###_config-snippet_### END
    server SRV_1 100.44.0.2:9000 enabled
    [...]
    backend default_plants-service_9000
    mode http
    balance roundrobin
    option forwardfor
    no option abortonclose
    default-server check
    ###_config-snippet_### BEGIN
    ### service:default_plants-service_9000/default/plants-service ###
    default-server proto fcgi
    use-fcgi-app php-fpm
    ###_config-snippet_### END
    server SRV_1 100.36.0.1:9000 enabled
    [...]

Tip

You can find the name of your haproxy-kubernetes-ingress pods using the command kubectl get pods -n haproxy-controller.

Test the configuration Jump to heading

Use curl to test the connection between the configured ingress controller, load balancer, and your deployed PHP microservices.

In the previous steps, you mounted a file into each of the PHP-FPM containers: grocery.php for the grocery container and plants.php for the plants container. The ingress controller will route requests to the appropriate Service based on the URL path. For example:

  1. To reach the grocery Service, use the following command, replacing yourdomain.com with your domain and replacing <NODEPORT> with the NodePort of your ingress controller. The request will go to the grocery Service since the URL path contains /grocery.

    Tip

    Use the kubectl get service command to find the NodePort value. It is the NodePort associated with port 80. In this example, it is 30901:

    nix
    kubectl get service -n haproxy-controller
    nix
    kubectl get service -n haproxy-controller
    output
    text
    NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
    service/haproxy-kubernetes-ingress NodePort 10.105.8.178 <none> 80:30901/TCP,443:32033/TCP,443:32033/UDP,1024:30609/TCP,6060:31356/TCP 27h
    output
    text
    NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
    service/haproxy-kubernetes-ingress NodePort 10.105.8.178 <none> 80:30901/TCP,443:32033/TCP,443:32033/UDP,1024:30609/TCP,6060:31356/TCP 27h
    nix
    curl http://yourdomain.com:<NODEPORT>/grocery/grocery.php
    nix
    curl http://yourdomain.com:<NODEPORT>/grocery/grocery.php
    output
    json
    {"bananas":3,"bread":2,"bacon":1}
    output
    json
    {"bananas":3,"bread":2,"bacon":1}

    Note that the response served is the contents of the script you defined earlier after PHP-FPM has executed the PHP code.

  2. To reach the plants Service, use the following command, replacing yourdomain.com with your domain and replacing <NODEPORT> with the NodePort of your ingress controller.

    nix
    curl http://yourdomain.com:<NODEPORT>/plants/plants.php
    nix
    curl http://yourdomain.com:<NODEPORT>/plants/plants.php
    output
    json
    {"tree":"oak","flower":"rose","vegetable":"carrot"}
    output
    json
    {"tree":"oak","flower":"rose","vegetable":"carrot"}
  3. Check the logs for the PHP-FPM pods to see that HAProxy routed the requests to PHP-FPM. This example retrieves the plants container’s logs. The same applies to the grocery container.

    nix
    kubectl logs plants-deployment-7ff8984f5f-l8gv8
    nix
    kubectl logs plants-deployment-7ff8984f5f-l8gv8
    output
    text
    [30-Jul-2024 14:25:27] NOTICE: fpm is running, pid 1
    [30-Jul-2024 14:25:27] NOTICE: ready to handle connections
    100.36.0.2 - 30/Jul/2024:14:30:28 +0000 "GET /plants.php" 200
    output
    text
    [30-Jul-2024 14:25:27] NOTICE: fpm is running, pid 1
    [30-Jul-2024 14:25:27] NOTICE: ready to handle connections
    100.36.0.2 - 30/Jul/2024:14:30:28 +0000 "GET /plants.php" 200

    Tip

    Find the names of your deployments using the command kubectl get deployments.

Conclusion Jump to heading

HAProxy provides an extensive set of routing and load balancing capabilities. The HAProxy Kubernetes Ingress Controller extends HAProxy’s well-known flexibility and customizability to Kubernetes’ ingress configuration, simplifying the migration of applications to Kubernetes, even traditional PHP-based applications, as you saw in this tutorial.

The HAProxy Enterprise Kubernetes Ingress Controller also presents a robust option for those requiring built-in WAF security, enterprise administration, and official support from HAProxy Technologies.

See also Jump to heading

Do you have any suggestions on how we can improve the content of this page?