DEV Community

Adam Gardner
Adam Gardner

Posted on

Hands on with flagd: Open source feature flagging

flagd is a fully open source feature flag system released as part of the OpenFeature project. Essentially, flagd in a fully-featured feature flag evaluation storage and backend evaluation system + an API and / or gRPC endpoint to interact and retrieve flag values.

flagd comes various forms: standalone binaries for every OS, a docker image or a Kubernetes Operator.

So how does it work?

Let's start with the "standalone" version of flagd. Download the latest binary for your OS from the releases page.

Extract the binary, add the executable bit (chmod +x flagd_...) and run the binary. You will see output like this:

% ./flagd_darwin_arm64 

         ______   __       ________   _______    ______      
        /_____/\ /_/\     /_______/\ /______/\  /_____/\     
        \::::_\/_\:\ \    \::: _  \ \\::::__\/__\:::_ \ \    
         \:\/___/\\:\ \    \::(_)  \ \\:\ /____/\\:\ \ \ \   
          \:::._\/ \:\ \____\:: __  \ \\:\\_  _\/ \:\ \ \ \  
           \:\ \    \:\/___/\\:.\ \  \ \\:\_\ \ \  \:\/.:| | 
            \_\/     \_____\/ \__\/\__\/ \_____\/   \____/_/        

Flagd is a simple command line tool for fetching and presenting feature flags to services. It is designed to conform to Open Feature schema for flag definitions.

Usage:
  flagd [command]
...
Enter fullscreen mode Exit fullscreen mode

Create your first flag

Let's create your very first flag: a simple String flag called basic-string which has two possible values: foo (which returns "bar") and bar (which returns "other"). The foo variant is set as the defaultValue which means "bar" should be returned. Save the following as a JSON file:

flags.json

{
  "flags": {
    "basic-string": {
      "state": "ENABLED",
      "defaultVariant": "foo",
      "variants": {
        "foo": "bar",
        "bar": "other"
      },
      "targeting": {}
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Now restart flagd and point it to your flags.json file:

./flagd start --uri file:flags.json
Enter fullscreen mode Exit fullscreen mode

You should see:

Flag Evaluation listening at [::]:8013  {"component": "service"}
Enter fullscreen mode Exit fullscreen mode

Retrieve a flag value

Open a new terminal window and request the basic-string flag:

curl -X POST "http://localhost:8013/flagd.evaluation.v1.Service/ResolveString" \ 
  -d '{"flagKey":"basic-string","context":{}}' -H "Content-Type: application/json"
Enter fullscreen mode Exit fullscreen mode

You should see:

{
  "value":"bar",
  "reason":"STATIC",
  "variant":"foo",
  "metadata":{}
}
Enter fullscreen mode Exit fullscreen mode

Update defaultValue at runtime

flagd updates flag values at runtime, without a restart.

Leave flagd running and update flags.json so that defaultValue is now "bar".

flags.json

{
  "flags": {
    "basic-string": {
      "state": "ENABLED",
      "defaultVariant": "bar",
      "variants": {
        "foo": "bar",
        "bar": "other"
      },
      "targeting": {}
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Re-execute the cURL command to retrieve the basic-string flag and you should see the value is now "other". :

curl -X POST "http://localhost:8013/flagd.evaluation.v1.Service/ResolveString" \ 
  -d '{"flagKey":"basic-string","context":{}}' -H "Content-Type: application/json"
Enter fullscreen mode Exit fullscreen mode
{
  "value":"other",
  "reason":"STATIC",
  "variant":"bar",
  "metadata":{}
}
Enter fullscreen mode Exit fullscreen mode

What about Kubernetes?

flagd works on Kubernetes too:

Install cert-manager if you don't have it already

Install the OpenFeature Operator

helm repo add openfeature https://open-feature.github.io/open-feature-operator/
helm repo update
helm upgrade --install openfeature openfeature/open-feature-operator
Enter fullscreen mode Exit fullscreen mode

Create the feature flag via a FeatureFlag CRD:

kubectl apply -f - <<EOF
apiVersion: core.openfeature.dev/v1beta1
kind: FeatureFlag
metadata:
  name: sample-flags
spec:
  featureFlagSpec:
    flags:
      "basic-string":
        state: "ENABLED"
        variants:
          "foo": "bar"
          "bar": "other"
        defaultVariant: "foo"
        targeting: {}
EOF
Enter fullscreen mode Exit fullscreen mode

Tell the operator where to find the flags by defining a FeatureFlagSource:

kubectl apply -f - <<EOF
apiVersion: core.openfeature.dev/v1beta1
kind: FeatureFlagSource
metadata:
  name: feature-flag-source
spec:
  sources:
  - source: default/sample-flags
    provider: kubernetes
  port: 8080
EOF
Enter fullscreen mode Exit fullscreen mode

Finally, enable those flags for your deployment by using the openfeature.dev/enabled and openfeature.dev/featureflagsource annotations:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: your-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: my-busybox-curl-app
  template:
    metadata:
      labels:
        app: my-busybox-curl-app
      annotations:
        # here are the annotations for OpenFeature Operator
        openfeature.dev/enabled: "true"
        openfeature.dev/featureflagsource: "default/feature-flag-source"
    spec:
      containers:
        - name: busybox
          image: yauritux/busybox-curl:latest
          ports:
            - containerPort: 80
          args:
            - sleep
            - "30000"
Enter fullscreen mode Exit fullscreen mode

From within your application (ie. the above pod), the flagd endpoints are available at localhost:8080 so you can do:

// From within the pod
curl --location 'http://localhost:8080/flagd.evaluation.v1.Service/ResolveString' --header 'Content-Type: application/json' --data '{ "flagKey":"basic-string"}'
Enter fullscreen mode Exit fullscreen mode

In a real application, rather than curl, you would probably use the OpenFeature SDK with the flagd provider.

That's all great, but how do I build that flag JSON?

As you've seen, flagd is very simple. Arguably the hardest part is defining the flags themselves. Guessing the JSON is no fun! Thankfully, the flagd playground provides demo code and a live testing playground which makes the JSON easy!

Top comments (0)