In this tutorial we will create your first Overboard script and generate the Kubernetes YAML config to a file.
- A Kubernetes cluster to learn on such as Kubernetes on Docker or minikube.
- A basic knowledge of using kubectl
- dotnet SDK installed
- Optionally, any IDE that supports F# (Visual Studio Code, IntelliJ Rider, Visual Studio, NeoVim)
Visual Studio Code with the Ionide is a great choice. See Setup your environment for more details.
Create a F# script file called deployment.fsx
Copy the following code into the script file:
// TODO: import from Nuget
#r "nuget:Overboard"
// open the required namespaces
open Overboard
open Overboard.Common
open Overboard.Workload
// define your k8s config
let theInvalidDeployment = k8s {
deployment {
pod {
container {
name "nginx"
image "nginx:latest"
workingDir "/test-dir"
}
}
}
}
// Write the YAML to infra.yaml file and get the list of validation issues
let validations = KubeCtlWriter.toYamlFile theInvalidDeployment "hello-world.yaml"
// Let's print out the validation errors
for err in validations do
eprintfn "%s" err.Message
"Deployment 'metadata.name' is required.
LabelSelector requires at least one of `matchLabels` or `matchExpressions`"
|
Now you can call the fsx file to generate your YAML config.
dotnet fsi deployment.fsx
|
If you run the apply command on your YAML file, you will see Kubernetes agrees with the validation errors.
kubectl apply -f hello-world.yaml
|
Let's address the validation errors that Overboard found.
- Call the
add_matchLabel
operation with a key/value pair for the label.
- Next, add the label to the pod using the
_labels
metadata operation, passing in a list of key/value pairs.
let theValidDeployment = k8s {
deployment {
"test-deployment"
replicas 2
add_matchLabel ("app", "nginx") // <- fix the validation error
pod {
_labels [("app", "nginx")] // <- fix the validation error
container {
name "nginx"
image "nginx:latest"
workingDir "/test-dir"
}
}
}
}
KubeCtlWriter.toYamlFile theValidDeployment "hello-world.yaml"
Our validation errors are gone and we have a valid Kubernetes configuration.
"apiVersion: apps/v1
kind: Deployment
metadata:
name: test-deployment
namespace: default
spec:
minReadySeconds: 0
progressDeadlineSeconds: 600
replicas: 2
revisionHistoryLimit: 10
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
namespace: default
spec:
containers:
- image: nginx:latest
name: nginx
resources:
limits:
cpu: 1000m
memory: 512Mi
requests:
cpu: 500m
memory: 256Mi
workingDir: /test-dir
restartPolicy: Always
"
|
Let's execute this deployment against our Kubernetes cluster to confirm it is indeed correct.
dotnet fsi deployment.fsx
kubectl apply -f hello-world.yaml
kubectl get deployments
|
You should get the message: deployment.apps/test-deployment created
In this tutorial you created your first Overboard script and generated the YAML. We saw how to get and print out the validation errors.
Finally, we saw how we can successfully deploy our generated script.
Congratulations! You have taken a turn toward a new way of configuring your infrastructure.
namespace Overboard
namespace Overboard.Common
namespace Overboard.Workload
val theInvalidDeployment: K8s
val k8s: K8sBuilder
val deployment: DeploymentBuilder
val pod: PodBuilder
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: name (string)
Calls ContainerBuilder.Name
custom operation: image (string)
Calls ContainerBuilder.Image
custom operation: workingDir (string)
Calls ContainerBuilder.WorkingDir
val validations: ValidationProblem list
module KubeCtlWriter
from Overboard.K8s
val toYamlFile: k8s: K8s -> filePath: string -> ValidationProblem list
val err: ValidationProblem
val eprintfn: format: Printf.TextWriterFormat<'T> -> 'T
<summary>Print to <c>stderr</c> using the given format, and add a newline.</summary>
<param name="format">The formatter.</param>
<returns>The formatted result.</returns>
<example>See <c>Printf.eprintfn</c> (link: <see cref="M:Microsoft.FSharp.Core.PrintfModule.PrintFormatLineToError``1" />) for examples.</example>
property ValidationProblem.Message: string with get
val output1: K8sOutput
val toYaml: k8s: K8s -> K8sOutput
val errorOutput1: string
K8sOutput.errors: ValidationProblem list
Multiple items
module List
from Microsoft.FSharp.Collections
<summary>Contains operations for working with values of type <see cref="T:Microsoft.FSharp.Collections.list`1" />.</summary>
<namespacedoc><summary>Operations for collections such as lists, arrays, sets, maps and sequences. See also
<a href="https://docs.microsoft.com/dotnet/fsharp/language-reference/fsharp-collection-types">F# Collection Types</a> in the F# Language Guide.
</summary></namespacedoc>
--------------------
type List<'T> =
| op_Nil
| op_ColonColon of Head: 'T * Tail: 'T list
interface IReadOnlyList<'T>
interface IReadOnlyCollection<'T>
interface IEnumerable
interface IEnumerable<'T>
member GetReverseIndex: rank: int * offset: int -> int
member GetSlice: startIndex: int option * endIndex: int option -> 'T list
static member Cons: head: 'T * tail: 'T list -> 'T list
member Head: 'T
member IsEmpty: bool
member Item: index: int -> 'T with get
...
<summary>The type of immutable singly-linked lists.</summary>
<remarks>Use the constructors <c>[]</c> and <c>::</c> (infix) to create values of this type, or
the notation <c>[1;2;3]</c>. Use the values in the <c>List</c> module to manipulate
values of this type, or pattern match against the values directly.
</remarks>
<exclude />
val map: mapping: ('T -> 'U) -> list: 'T list -> 'U list
<summary>Builds a new collection whose elements are the results of applying the given function
to each of the elements of the collection.</summary>
<param name="mapping">The function to transform elements from the input list.</param>
<param name="list">The input list.</param>
<returns>The list of transformed elements.</returns>
<example id="map-1"><code lang="fsharp">
let inputs = [ "a"; "bbb"; "cc" ]
inputs |> List.map (fun x -> x.Length)
</code>
Evaluates to <c>[ 1; 3; 2 ]</c></example>
val toSeq: list: 'T list -> seq<'T>
<summary>Views the given list as a sequence.</summary>
<param name="list">The input list.</param>
<returns>The sequence of elements in the list.</returns>
<example id="toseq-1"><code lang="fsharp">
let inputs = [ 1; 2; 5 ]
inputs |> List.toSeq
</code>
Evaluates to <c>seq { 1; 2; 5 }</c>.
</example>
val arr: seq<string>
Multiple items
module String
from Overboard
--------------------
module String
from Microsoft.FSharp.Core
<summary>Functional programming operators for string processing. Further string operations
are available via the member functions on strings and other functionality in
<a href="http://msdn2.microsoft.com/en-us/library/system.string.aspx">System.String</a>
and <a href="http://msdn2.microsoft.com/library/system.text.regularexpressions.aspx">System.Text.RegularExpressions</a> types.
</summary>
<category>Strings and Text</category>
val concat: sep: string -> strings: seq<string> -> string
<summary>Returns a new string made by concatenating the given strings
with separator <c>sep</c>, that is <c>a1 + sep + ... + sep + aN</c>.</summary>
<param name="sep">The separator string to be inserted between the strings
of the input sequence.</param>
<param name="strings">The sequence of strings to be concatenated.</param>
<returns>A new string consisting of the concatenated strings separated by
the separation string.</returns>
<exception cref="T:System.ArgumentNullException">Thrown when <c>strings</c> is null.</exception>
<example id="concat-1"><code lang="fsharp">
let input1 = ["Stefan"; "says:"; "Hello"; "there!"]
input1 |> String.concat " " // evaluates "Stefan says: Hello there!"
let input2 = [0..9] |> List.map string
input2 |> String.concat "" // evaluates "0123456789"
input2 |> String.concat ", " // evaluates "0, 1, 2, 3, 4, 5, 6, 7, 8, 9"
let input3 = ["No comma"]
input3 |> String.concat "," // evaluates "No comma"
</code></example>
namespace System
type Environment =
static member Exit: exitCode: int -> unit
static member ExpandEnvironmentVariables: name: string -> string
static member FailFast: message: string -> unit + 1 overload
static member GetCommandLineArgs: unit -> string[]
static member GetEnvironmentVariable: variable: string -> string + 1 overload
static member GetEnvironmentVariables: unit -> IDictionary + 1 overload
static member GetFolderPath: folder: SpecialFolder -> string + 1 overload
static member GetLogicalDrives: unit -> string[]
static member SetEnvironmentVariable: variable: string * value: string -> unit + 1 overload
static member CommandLine: string
...
<summary>Provides information about, and means to manipulate, the current environment and platform. This class cannot be inherited.</summary>
property System.Environment.NewLine: string with get
<summary>Gets the newline string defined for this environment.</summary>
<returns><see langword="\r\n" /> for non-Unix platforms, or <see langword="\n" /> for Unix platforms.</returns>
val theValidDeployment: K8s
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>
custom operation: _labels ((string * string) list)
Calls PodBuilder.Labels
<summary>
Labels for the Pod
</summary>
val output2: K8sOutput
val content2: string
K8sOutput.content: string