Install the Apigee Operator for Kubernetes for Apigee hybrid

This page applies to Apigee and Apigee hybrid.

View Apigee Edge documentation.

This page describes the steps required to install and configure the Apigee Operator for Kubernetes for Apigee hybrid. To learn more about the benefits of using the Apigee Operator for Kubernetes, see Apigee Operator for Kubernetes overview.

If you are not using Apigee hybrid, see Install the Apigee Operator for Kubernetes to install the Apigee Operator for Kubernetes for Apigee.

Before you begin

Before you begin, make sure that you have the following:

Required roles

For the permissions that you need to set up the resources required to install and use the Apigee Operator for Kubernetes, ask your administrator to grant you the following IAM roles on the organization:

  • Create and manage service accounts: Service Account Admin (roles/iam.serviceAccountAdmin)
  • Create and manage Apigee resources: Apigee Admin (roles/apigee.admin)

For more information about granting roles, see Manage access to projects, folders, and organizations.

You might also be able to get the required permissions through custom roles or other predefined roles.

Required set up tasks

Before you install the Apigee Operator for Kubernetes, make sure to complete the following tasks to set up the resources you need to use the feature:

  1. Install Apigee hybrid using version 1.15.0 or later. see The big picture for instructions to install Apigee hybrid.
  2. Create a Kubernetes cluster in a cloud provider that supports Istio Gateway, such as Google Cloud, Azure, or Amazon.
  3. Install Istio Gateway into your K8s cluster:
    • For clusters on GKE:
      kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.1.0/standard-install.yaml
      curl -L https://istio.io/downloadIstio | sh -
      cd 1.6.11-asm.1
      export PATH=$PWD/bin:$PATH
      istioctl install --set profile=minimal --set values.global.platform=gke -y
      
    • For clusters on other providers:
      kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.1.0/standard-install.yaml
      curl -L https://istio.io/downloadIstio | sh -
      cd 1.6.11-asm.1
      export PATH=$PWD/bin:$PATH
      istioctl install --set profile=minimal -y
      
  4. Deploy Istio Gateway into your Kubernetes cluster.
    1. Create a file named gateway.yaml with the following contents to deploy the Istio Gateway with the following contents:
      #gateway.yaml
      apiVersion: gateway.networking.k8s.io/v1
      kind: Gateway
      metadata:
        name: istio-gateway
        namespace: default
        annotations:
          service.beta.kubernetes.io/port_80_health-probe_protocol: tcp
      spec:
        gatewayClassName: istio
        listeners:
        - name: default
          hostname: "*.httpbin.com"
          port: 80
          protocol: HTTP
          allowedRoutes:
            namespaces:
              from: All
      
    2. Apply the file to your cluster with the following command:
      kubectl apply -f gateway.yaml
      

Verify the Istio Gateway setup (optional)

For the purposes of this guide, we recommend that you deploy a sample httpbin application in the default namespace to test the gateway you deployed.

  1. Deploy a backend application to your Kubernetes cluster to test the gateway.
    1. Create a new file named target.yaml with the following content into the new file
      kubectl apply -f - <<EOF
      apiVersion: v1
      kind: ServiceAccount
      metadata:
        name: httpbin
      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: httpbin
        labels:
          app: httpbin
          service: httpbin
      spec:
        ports:
        - name: http
          port: 8000
          targetPort: 8080
        selector:
          app: httpbin
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: httpbin
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: httpbin
            version: v1
        template:
          metadata:
            labels:
              app: httpbin
              version: v1
          spec:
            serviceAccountName: httpbin
            containers:
            - image: docker.io/mccutchen/go-httpbin:v2.15.0
              imagePullPolicy: IfNotPresent
              name: httpbin
              ports:
              - containerPort: 8080
      EOF
      
    2. Deploy the HTTPRoute resource to your cluster to map traffic from the Gateway to your backend service.

      For the purposes of this guide, we recommend that you deploy an external Gateway and HTTPRoute, following the steps in Create an HTTPRoute.

      For more information on the HTTPRoute resource, see Deploy the HTTPRoute (for internal Gateways) or Create an HTTPRoute (for external Gateways).

      1. Create an HTTPRoute following the instructions in create the HTTPRoute using the following yaml configuration:
        apiVersion: gateway.networking.k8s.io/v1
        kind: HTTPRoute
        metadata:
          name: http-bin-route
          namespace: default
        spec:
          parentRefs:
          - name: istio-gateway
            namespace: default
          hostnames: ["example.httpbin.com"]
          rules:
          - matches:
            - path:
                type: PathPrefix
                value: /get
            backendRefs:
            - name: httpbin
              port: 8000
        
      2. Apply the file to your cluster:
        kubectl apply -f httproute.yaml
        
    3. Verify the GKE Gateway setup to confirm that it is working as expected.
      1. Get the Gateway details using the following command
        kubectl get gateway global-ext-lb1
        

        The output should appear similar to the following:

        NAME            CLASS   ADDRESS        PROGRAMMED   AGE
        istio-gateway   istio   34.54.193.72   True         11d
        

        Confirm that an IP address is assigned to the Gateway and that the value of PROGRAMMED is True.

      2. Describe the Gateway to confirm the route is attached:
        kubectl describe gateway istio-gateway
        

        The output should look similar to the following:

        ...
          Listeners:
            Attached Routes: 1
            Conditions:
              Last Transition Time:  2024-10-03T03:10:17Z
        ...
        

        Confirm that the value of Attached Routes is 1, indicating that the route is attached.

      3. Send a request to the Gateway
        curl http://GATEWAY_IP_ADDRESS/get \
          -H "Host: example.httpbin.com"
        

        Where: GATEWAY_IP_ADDRESS is the IP address of the Gateway. You can retrieve the Gateway IP address using the following command, where GATEWAY_NAME is the name of the Gateway:

        kubectl get gateways.gateway.networking.k8s.io GATEWAY_NAME -o=jsonpath="{.status.addresses.value}"
        

        For example:

        curl http://34.54.193.72/get -H "Host: example.httpbin.com"
        

        The response should appear similar to the following:

        {
            "args": {},
            "headers": {
              "Accept": "*/*",
              "Host": "http://example.httpbin.com",
              "User-Agent": "curl/8.7.1",
              "X-Cloud-Trace-Context": "2bb8a80e29e80662ff9cb89971c447d9/13083106619927322701"
            },
            "origin": "67.164.1.10,34.54.193.72",
            "url": "http://example.httpbin.com/get"
        }
        

    Install the Apigee Operator for Kubernetes

    This procedure describes the steps required to install and configure the Apigee Operator for Kubernetes.

    Install and configure the Apigee Operator for Kubernetes

    The following sections describe the steps required to install and configure the Apigee Operator for Kubernetes:

    1. Set environment variables.
    2. Create and configure the APIM service account.
    3. Install the Apigee Operator for Kubernetes.
    4. Create an Apigee Hybrid environment.
    5. Install the Apigee Hybrid Environment using helm.

    Set environment variables

    In the Google Cloud project that contains your Apigee instance, use the following command to set environment variables:

    export PROJECT_ID=PROJECT_ID
    export APIGEE_ORG=APIGEE_ORG
    

    Where:

    • PROJECT_ID is the ID of the project with your Apigee Hybrid instance.
    • APIGEE_ORG is the Organization name of your Apigee Hybrid instance.

    Confirm that the environment variables are set correctly with the following command:

    echo $PROJECT_ID $APIGEE_ORG
    

    Create and configure the APIM service account

    Create a service account to connect to the Apigee Hybrid config plane.

    1. Create the apigee-apim-gsa service account to connect to Google Cloud services
    2. gcloud iam service-accounts create apigee-apim-gsa
      
    3. Grant the Apigee Admin role to the service account you created using the following command. This role is required to create and manage Apigee resources
      gcloud projects add-iam-policy-binding $PROJECT_ID \
        --member "serviceAccount:apigee-apim-gsa@$PROJECT_ID.iam.gserviceaccount.com" \
        --role "roles/apigee.admin"
      
    4. Download the corresponding json key file for the service account.
      1. Create and download the $PROJECT_ID-apigee-apim-gsa.json key file with the following command:
        gcloud iam service-accounts keys create $PROJECT_ID-apigee-apim-gsa.json \
          --iam-account=apigee-apim-gsa@$PROJECT_ID.iam.gserviceaccount.com
          --project=$PROJECT_ID
                
      2. Verify that the file downloaded correctly:
        ls $PROJECT_ID-apigee-apim-gsa.json
                

    Install the Apigee Operator for Kubernetes

    Install the Kubernetes custom resources definitions (CRDs) and Apigee Operator for Kubernetes:

    1. Create a namespace for the Apigee Operator for Kubernetes
      kubectl create namespace apim
      
    2. Install the Apigee Operator for Kubernetes custom resource definitions (CRDs):
      helm install apigee-apim-crds -n apim \
        oci://us-docker.pkg.dev/apigee-release/apigee-k8s-tooling-helm-charts/apigee-apim-operator-crds \
        --version 1.1.0 \
        --atomic
      
    3. Install the Apigee Operator for Kubernetes:
      helm install apigee-apim-operator -n apim \
        oci://us-docker.pkg.dev/apigee-release/apigee-k8s-tooling-helm-charts/apigee-apim-operator-helm \
        --version 1.1.0 \
        --set serviceAccount=apigee-apim-gsa@$PROJECT_ID.iam.gserviceaccount.com \
        --set apigeeOrg=$APIGEE_ORG \
        --set apigeeEnv=ENV_NAME \
        --set-file serviceAccountKeyFileContent=$PROJECT_ID-apigee-apim-gsa-key.json \
        --atomic
      

      Where ENV_NAME is the name of the Apigee Hybrid environment in which you want to install the Apigee Operator for Kubernetes.

    4. Confirm that the installation completed successfully:
      helm list -n apim
      

      The output should look similar to the following:

      NAME  NAMESPACE  REVISION  UPDATED  STATUS  CHART  APP VERSION
      apigee-apim-crds  apim  1  2025-09-01 00:17:03.399810627 +0000 UTC  deployed  apigee-apim-operator-crds-1.1.0  1.1.0
      apigee-apim-operator  apim  1  2025-09-01 00:15:00.362829981 +0000 UTC  deployed  apigee-apim-operator-helm-1.1.0  1.1.0
      
    5. Confirm that the Kubernetes service account (KSA) was created with the required annotation:
      kubectl describe serviceaccounts apim-ksa -n apim
      

      The output should look similar to the following:

      Name:                apim-ksa
      Namespace:           apim
      ...
      Annotations:         iam.gke.io/gcp-service-account: apigee-apim-gsa@my-project-id.iam.gserviceaccount.com
      
    6. Confirm that the Apigee Operator for Kubernetes is up and running in the cluster's pods:
      kubectl get pods -n apim
      

      The output should look similar to the following:

      NAME  READY  STATUS  RESTARTS  AGE
      apigee-apim-operator-8559d4994b-h55fl   1/1     Running   0   8m34s
      

      If the STATUS is not Running, or READY does not display 1/1, see Troubleshoot the Apigee Operator for Kubernetes to troubleshoot the installation.

    Create an Apigee hybrid environment

    To use the Apigee Operator for Kubernetes in Apigee Hybrid, you must create an environment with a special flag for service extension.

    1. Get a token to authenticate to the Apigee API.

      On the command line, get your gcloud authentication credentials, as the following example shows:

      TOKEN=$(gcloud auth print-access-token)

      To check that your token was populated, use echo, as the following example shows:

      echo $TOKEN

      This should display your token as an encoded string.

      For more information, see gcloud command-line tool overview.

    2. Create the environment using one of the following commands:
      • For Subscription 2021 organizations:
        curl -X POST "https://apigee.googleapis.com/v1/organizations/$APIGEE_ORG/environments" -H \
          "Authorization: Bearer $TOKEN" -H "content-type:application/json" \
            -d '{
              "name": "ENV_NAME",
              "displayName": "ENV_DISPLAY_NAME",
              "state": "ACTIVE",
              "deploymentType": "PROXY",
              "apiProxyType": "PROGRAMMABLE",
              "properties": {
                "property": [
                  {
                    "name": "apigee-service-extension-enabled",
                    "value": "true"
                  }
                ]
              }
            }'
        

        Where ENV_NAME is the name of the environment you want to create.

      • For Subscription 2024 and Pay-as-you-go orgs:
        curl -i -X POST -H "Authorization: Bearer $TOKEN"  "https://apigee.googleapis.com/v1/organizations/$APIGEE_ORG/environments" -H "Content-Type:application/json" -d '{
          "name": "ENV_NAME",
          "displayName": "ENV_NAME",
          "state": "ACTIVE",
          "deploymentType": "PROXY",
          "apiProxyType": "PROGRAMMABLE",
          "type" : "ENV_TYPE",
          "properties": {
            "property": [
              {
                "name": "apigee-service-extension-enabled",
                "value": "true"
              }
            ]
          }
        }'
        

        Where:

        • ENV_NAME is the name of the environment you want to create.
        • ENV_TYPE is the type of the environment you want to create. For example, INTERMEDIATE or COMPREHENSIVE.

      Check that the environment was created successfully:

      curl -i -H "Authorization: Bearer $TOKEN" \
        "https://apigee.googleapis.com/v1/organizations/$APIGEE_ORG/environments"
      

      See Create an environment in the Apigee hybrid installation instructions for more information.

    3. Create an Environment Group with the following command:
      curl -i -X POST -H "Authorization: Bearer $TOKEN"  "https://apigee.googleapis.com/v1/organizations/$APIGEE_ORG/envgroups" -H "Content-Type:application/json" -d '{
           "name": "'"$ENV_GROUP"'",
           "hostnames":["'"$DOMAIN"'"]
         }'
      

      Where:

      • ENV_GROUP (Required) The environment name can contain lowercase letters, dashes, and numbers and must start with a lowercase letter. This name will be used as the identifier and cannot be changed after creation.
      • DOMAIN (Required) This is the hostname that all proxies deployed to environments within this group will use. This should be a domain you manage. The address can be the domain itself, like example.com or it can include a subdomain like my-proxies.example.com. If you don't have a managed domain, you can enter a placeholder for now. You can change the domain address later.

      See Create an environment group in the Apigee hybrid installation instructions for more information.

    4. Attach the Environment to the Environment Group you just created with the following command:
      curl -i -X POST -H "Authorization: Bearer $TOKEN"  "https://apigee.googleapis.com/v1/organizations/$APIGEE_ORG/envgroups/$ENV_GROUP/attachments" -H "Content-Type:application/json" -d '{
           "environment": "'"$ENV_NAME"'",
         }'
      

    Install the Apigee Hybrid Environment using helm

    The procedure to install the new environment in the Apigee Hybrid cluster is similar to how you installed other environments in your cluster. This is needed to add new environment and environment group details to our Kubernetes cluster in which Apigee Hybrid was installed.

    1. Generate the TLS certificate for the Environment Group domain with the following command:
      openssl req -nodes -new -x509 -keyout $APIGEE_HELM_CHARTS_HOME/apigee-virtualhost/certs/keystore_$ENV_GROUP.key -out $APIGEE_HELM_CHARTS_HOME/apigee-virtualhost/certs/keystore_$ENV_GROUP.pem -subj "/CN=$DOMAIN" -addext "subjectAltName = DNS:$DOMAIN" -days 3650
      

      Where:

      • APIGEE_HELM_CHARTS_HOME (Required) Directory where you downloaded the Apigee Helm Charts during the Apigee Hybrid Installation.
    2. Base64 encode the TLS public certificate with the following command:
      cat $APIGEE_HELM_CHARTS_HOME/apigee-virtualhost/certs/keystore_$ENV_GROUP.pem | base64 -w0 > $APIGEE_HELM_CHARTS_HOME/apigee-virtualhost/certs/keystore_$ENV_GROUP.pem.base64
      
    3. Update the overrides.yaml file with the following entry under envs
      - name: ENV_NAME
        serviceAccountPaths:
          # Provide the path relative to the apigee-env chart directory.
          synchronizer: SYNCHRONIZER_SERVICE_ACCOUNT_FILEPATH
          # For example: "PROJECT_ID-apigee-synchronizer.json"
          runtime: RUNTIME_SERVICE_ACCOUNT_FILEPATH
          # For example: "PROJECT_ID-apigee-runtime.json"
          udca: UDCA_SERVICE_ACCOUNT_FILEPATH
          # For example: "PROJECT_ID-apigee-udca.json"
      

      Where *_SERVICE_ACCOUNT_FILEPATH (Required) is the json key file of the service account you used during the Apigee Hybrid installation, see Create the overrides in the Apigee hybrid installation instructions for more information.

    4. Add following entry in the overrides.yaml file under virtualhosts
      - name: 
        selector:
          app: apigee-ingressgateway
          ingress_name: INGRESS_NAME
        sslCertPath: certs/keystore_$ENV_GROUP.pem
        sslKeyPath: certs/keystore_$ENV_GROUP.key
      

      Where INGRESS_NAME (Required) is the name of the Apigee ingress gateway for your deployment, see here for more information.

    5. Install the environment and environment group
      1. Install the environment.

        You must install one environment at a time. Specify the environment with --set env=ENV_NAME. If you have set the $ENV_NAME environment variable in your shell, you can use that in the following commands:

        Dry run:

        helm upgrade ENV_RELEASE_NAME apigee-env/ \
          --install \
          --namespace APIGEE_NAMESPACE \
          --atomic \
          --set env=$ENV_NAME \
          -f overrides.yaml \
          --dry-run=server
        

          ENV_RELEASE_NAME is a name used to keep track of installation and upgrades of the apigee-env chart. This name must be unique from the other Helm release names in your installation. Usually this is the same as ENV_NAME. However, if your environment has the same name as your environment group, you must use different release names for the environment and environment group, for example dev-env-release and dev-envgroup-release. For more information on releases in Helm, see Three big concepts in the Helm documentation.

        Install the chart:

        helm upgrade ENV_RELEASE_NAME apigee-env/ \
          --install \
          --namespace APIGEE_NAMESPACE \
          --atomic \
          --set env=$ENV_NAME \
          -f overrides.yaml
        

        Verify it is up and running by checking the state of the respective env:

        kubectl -n APIGEE_NAMESPACE get apigeeenv
        
        NAME                    STATE       AGE   GATEWAYTYPE
        apigee-org1-dev-1       running     2d
        
      2. Install the environment groups (virtualhosts).
        1. You must install one environment group (virtualhost) at a time. Specify the environment group with --set envgroup=ENV_GROUP. If you have set the $ENV_GROUP environment variable in your shell, you can use that in the following commands. Repeat the following commands for each env group mentioned in your overrides.yaml file:

          Dry run:

          helm upgrade ENV_GROUP_RELEASE_NAME apigee-virtualhost/ \
            --install \
            --namespace APIGEE_NAMESPACE \
            --atomic \
            --set envgroup=$ENV_GROUP \
            -f overrides.yaml \
            --dry-run=server
          

            ENV_GROUP_RELEASE_NAME is a name used to keep track of installation and upgrades of the apigee-virtualhosts chart. This name must be unique from the other Helm release names in your installation. Usually this is the same as ENV_GROUP. However, if your environment group has the same name as an environment in your installation, you must use different release names for the environment group and environment, for example dev-envgroup-release and dev-env-release. For more information on releases in Helm, see Three big concepts in the Helm documentation.

          Install the chart:

          helm upgrade $ENV_GROUP_RELEASE_NAME apigee-virtualhost/ \
            --install \
            --namespace APIGEE_NAMESPACE \
            --atomic \
            --set envgroup=$ENV_GROUP \
            -f overrides.yaml
          

      Your Apigee Hybrid org is now ready with the new environment to test service extension.

      Continue with the procedures in Create an APIMExtensionPolicy to create an extension policy.