The real power of Overboard is not only the awesome declarative builder syntax enabled by F# but also that we can leverage the full power of a programming language instead of some hacky templating language.
In the example below we define a function that defines a deployment and a service based on the application name and port number passed to the function.
The function nomalizes the name by lowercasing it and stripping any special characters from it. This is a great way to standardize on naming conventions without always requiring that everyone always remembers the standards.
open System
open Overboard
open Overboard.Common
open Overboard.Workload
open Overboard.Service
/// Returns a deployment and service for `appName`
let publicApi appName portNumber =
/// Lowercase the name and allow only letters and digits
let normalize (name: string) =
name.ToLowerInvariant().ToCharArray()
|> Array.filter Char.IsLetterOrDigit
|> String
let normalizedName = normalize appName
let matchOn = ("app", normalizedName)
k8s {
deployment {
$"{normalizedName}-deploy"
_labels [matchOn]
replicas 2
add_matchLabel ("app", normalizedName)
pod {
$"{normalizedName}-pod"
_labels [matchOn]
container {
"nginx"
image "nginx"
}
}
}
service {
$"{normalizedName}-service"
_labels [matchOn]
typeOf ServiceType.NodePort
matchLabel matchOn
servicePort {
port portNumber
protocol Protocol.TCP
}
}
}
// Use the `publicApi` function to create 2 lists or resources and combine them into a new `K8s` instance.
let k8sConfig = k8s {
publicApi "Checkout" 80
publicApi "Payments" 81
}
// Get the output content and validation errors
let k8sOutput = KubeCtlWriter.toYaml k8sConfig
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: checkout
name: checkout-deploy
namespace: default
spec:
minReadySeconds: 0
progressDeadlineSeconds: 600
replicas: 2
revisionHistoryLimit: 10
selector:
matchLabels:
app: checkout
template:
metadata:
labels:
app: checkout
name: checkout-pod
namespace: default
spec:
containers:
- image: nginx
name: nginx
resources:
limits:
cpu: 1000m
memory: 512Mi
requests:
cpu: 500m
memory: 256Mi
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
labels:
app: checkout
name: checkout-service
namespace: default
spec:
ports:
- port: 80
protocol: TCP
selector:
app: checkout
type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: payments
name: payments-deploy
namespace: default
spec:
minReadySeconds: 0
progressDeadlineSeconds: 600
replicas: 2
revisionHistoryLimit: 10
selector:
matchLabels:
app: payments
template:
metadata:
labels:
app: payments
name: payments-pod
namespace: default
spec:
containers:
- image: nginx
name: nginx
resources:
limits:
cpu: 1000m
memory: 512Mi
requests:
cpu: 500m
memory: 256Mi
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
labels:
app: payments
name: payments-service
namespace: default
spec:
ports:
- port: 81
protocol: TCP
selector:
app: payments
type: NodePort
val makeYaml: text: 'a -> string
val text: 'a
namespace System
namespace Overboard
namespace Overboard.Common
namespace Overboard.Workload
namespace Overboard.Service
val publicApi: appName: string -> portNumber: int -> K8s
Returns a deployment and service for `appName`
val appName: string
val portNumber: int
val normalize: (string -> String)
Lowercase the name and allow only letters and digits
val name: string
Multiple items
val string: value: 'T -> string
<summary>Converts the argument to a string using <c>ToString</c>.</summary>
<remarks>For standard integer and floating point values the and any type that implements <c>IFormattable</c><c>ToString</c> conversion uses <c>CultureInfo.InvariantCulture</c>. </remarks>
<param name="value">The input value.</param>
<returns>The converted string.</returns>
<example id="string-example"><code lang="fsharp"></code></example>
--------------------
type string = String
<summary>An abbreviation for the CLI type <see cref="T:System.String" />.</summary>
<category>Basic Types</category>
String.ToLowerInvariant() : string
type Array =
interface ICollection
interface IEnumerable
interface IList
interface IStructuralComparable
interface IStructuralEquatable
interface ICloneable
member Clone: unit -> obj
member CopyTo: array: Array * index: int -> unit + 1 overload
member GetEnumerator: unit -> IEnumerator
member GetLength: dimension: int -> int
...
<summary>Provides methods for creating, manipulating, searching, and sorting arrays, thereby serving as the base class for all arrays in the common language runtime.</summary>
val filter: predicate: ('T -> bool) -> array: 'T[] -> 'T[]
<summary>Returns a new collection containing only the elements of the collection
for which the given predicate returns "true".</summary>
<param name="predicate">The function to test the input elements.</param>
<param name="array">The input array.</param>
<returns>An array containing the elements for which the given predicate returns true.</returns>
<exception cref="T:System.ArgumentNullException">Thrown when the input array is null.</exception>
<example id="filter-1"><code lang="fsharp">
let inputs = [| 1; 2; 3; 4 |]
inputs |> Array.filter (fun elm -> elm % 2 = 0)
</code>
Evaluates to <c>[| 2; 4 |]</c></example>
[<Struct>]
type Char =
member CompareTo: value: char -> int + 1 overload
member Equals: obj: char -> bool + 1 overload
member GetHashCode: unit -> int
member GetTypeCode: unit -> TypeCode
member ToString: unit -> string + 2 overloads
static member ConvertFromUtf32: utf32: int -> string
static member ConvertToUtf32: highSurrogate: char * lowSurrogate: char -> int + 1 overload
static member GetNumericValue: c: char -> float + 1 overload
static member GetUnicodeCategory: c: char -> UnicodeCategory + 1 overload
static member IsAscii: c: char -> bool
...
<summary>Represents a character as a UTF-16 code unit.</summary>
Char.IsLetterOrDigit(c: char) : bool
Char.IsLetterOrDigit(s: string, index: int) : bool
Multiple items
type String =
interface IEnumerable<char>
interface IEnumerable
interface ICloneable
interface IComparable
interface IComparable<string>
interface IConvertible
interface IEquatable<string>
new: value: nativeptr<char> -> unit + 8 overloads
member Clone: unit -> obj
member CompareTo: value: obj -> int + 1 overload
...
<summary>Represents text as a sequence of UTF-16 code units.</summary>
--------------------
String(value: nativeptr<char>) : String
String(value: char[]) : String
String(value: ReadOnlySpan<char>) : String
String(value: nativeptr<sbyte>) : String
String(c: char, count: int) : String
String(value: nativeptr<char>, startIndex: int, length: int) : String
String(value: char[], startIndex: int, length: int) : String
String(value: nativeptr<sbyte>, startIndex: int, length: int) : String
String(value: nativeptr<sbyte>, startIndex: int, length: int, enc: Text.Encoding) : String
val normalizedName: String
val matchOn: string * String
val k8s: K8sBuilder
val deployment: DeploymentBuilder
custom operation: _labels ((string * string) list)
Calls DeploymentBuilder.Labels
<summary>
Labels for the Deployment
</summary>
custom operation: replicas (int)
Calls DeploymentBuilder.Replicas
custom operation: add_matchLabel (string * string)
Calls DeploymentBuilder.MatchLabel
<summary>
Add a single label selector to the Deployment.
</summary>
val pod: PodBuilder
custom operation: _labels ((string * string) list)
Calls PodBuilder.Labels
<summary>
Labels for the Pod
</summary>
val container: ContainerBuilder
<summary>
A single application container that you want to run within a pod.
https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#Container
</summary>
custom operation: image (string)
Calls ContainerBuilder.Image
val service: ServiceBuilder
custom operation: _labels ((string * string) list)
Calls ServiceBuilder.Labels
<summary>
Labels for the Service
</summary>
custom operation: typeOf (ServiceType)
Calls ServiceBuilder.Type
<summary>
Type of the Service.
</summary>
type ServiceType =
| ClusterIP
| ExternalName
| NodePort
| LoadBalancer
override ToString: unit -> string
union case ServiceType.NodePort: ServiceType
custom operation: matchLabel (string * string)
Calls ServiceBuilder.MatchLabel
<summary>
Add a single label selector to the Service.
</summary>
val servicePort: ServicePortBuilder
custom operation: port (int)
Calls ServicePortBuilder.Port
custom operation: protocol (Protocol)
Calls ServicePortBuilder.Protocol
type Protocol =
| TCP
| UDP
| SCTP
override ToString: unit -> string
static member combine: p1: Protocol -> p2: Protocol -> Protocol
union case Protocol.TCP: Protocol
val k8sConfig: K8s
val k8sOutput: K8sOutput
module KubeCtlWriter
from Overboard.K8s
val toYaml: k8s: K8s -> K8sOutput
K8sOutput.content: string