Skip to content
This repository was archived by the owner on Dec 21, 2021. It is now read-only.

Added first version of Readme #35

Merged
merged 11 commits into from
Jan 25, 2021
98 changes: 98 additions & 0 deletions README.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# Stackable Agent

## Purpose
This agent is the component in the Stackable stack which is run locally on all nodes to enact changes that are necessary to deploy and manager the software components that are managed by Stackable.

The agent behaves similar to a https://github.com/virtual-kubelet/virtual-kubelet[virtual kubelet], but is not implemented using the virtual kubelet framework.
Instead it is based on the https://github.com/deislabs/krustlet[Krustlet], which is under active development by Microsoft.

The agent registers itself as a node with a kube-apiserver will be considered by the Kubernetes scheduler for workloads (pods).
To avoid _normal_ Kubernetes pods being scheduled on the Stackable agent (it would not know what to do with these) the agent assigns the following taints to its node object:

|===
|Taint |Type|Value

|kubernetes.io/arch
|NoSchedule
|stackable-linux

|kubernetes.io/arch
|NoExecute
|stackable-linux
|===

These taints _suggest_ to the Kubernetes scheduler that only pods with matching tolerations should be scheduled on this node.

## Installation
### Build from source
Building from source is fairly straightforward if you have the rust toolchain installed.
If you need to install this, generally the recommended way is to use https://rustup.rs/[rustup].

After rust is installed simply run

cargo build

To create the binary file in _target/debug_.

### Download binary
We do not at this time provide pre-compiled binaries, as we are still in the process of setting up the build jobs to create these.
This readme will be updated as soon as binary downloads are available!

### OS Packages
We do not at this time provide os packages, that is due to change in the near future and this readme will be updated accordingly!

## Configuration

### Command Line Parameters

WARNING: Due to https://github.com/stackabletech/agent/issues/34[#34] it is not currently possible to specify these parameters directly on the commandline, please use a config file instead.

The agent accepts the following command line parameters:

include::config/commandline_args.adoc[]

### Config File
In addition to directly specifying them on the command line, the agent allows specifying a config file via the environment variable _CONFIG_FILE_. Values specified in the file will have to adhere to the format _--parameter=value_.

This file can contain all command line parameters as well and will be parsed before the actual command line.
For parameters that are present in the file and on the command line, the command line will take precedence, unless it is a parameter that can be specified multiple times, in which case paramaters from both, file and commandline, will be used.

.Example config file
--package-directory=/opt/stackable/agent/work/packages
--config-directory=/etc/stackable/agent
--server-cert-file=/etc/stackable/agent/secure/cert.crt
--server-key-file=/etc/stackable/agent/secure/key.key

### Kubernetes Config
The agent uses the default way of looking for a kube-apiserver, so if your system is already set up to connect to Kubernetes with kubectl you should be good to go right of the bat.

The default location for the Kubernetes client config is _~/.kube/config_, if you want to change this location you can override this via the _KUBECONFIG_ environment variable.

export KUBECONFIG=/etc/stackable/agent/kubeconfig


### Certificates
The agent requires a keypair and signed certificate to start a webserver which can be used to handle callbacks.
If these are not specified on the commandline, the agent will create a keypair, upload a certificate signing request to Kubernetes and wait for the certificate before continuing.
These steps require a certificate manager to be set up and running in your Kubernetes cluster, which may or may not be the case.

You can also manually create these files and specify them on the command line.
The following example shows how to create these files using https://github.com/OpenVPN/easy-rsa[easy-rsa], but this can be done in any number of different ways as well.

./easyrsa init-pki
./easyrsa build-ca
./easyrsa gen-req krustlet1
./easyrsa import-req pki/reqs/krustlet1.req krustlet1-req
./easyrsa sign-req serverClient krustlet1-req
# Convert key to pksc8 format
openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in pki/private/krustlet1.key -out pkcs8.key

## Contributing
The agent is developed as an open source tool and we absolutely welcome any and all contributions!
Don't hesitate to drop us a line at info@stackable.de or reach out directly to any of our committers / contributors.

We will run a bi-weekly dev call during which we will discuss current development, issues, our children and the general state of the world.
Please feel free to drop in if you have the time!

Dial in info coming soon!

106 changes: 106 additions & 0 deletions config/commandline_args.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@



### config-directory

*Default value*: /opt/stackable/config

*Required*: false

*Multiple values:*: false


This directory will serve as starting point for all log files which this service creates.Every service will get its own subdirectories created within this directory - for every service start a new subdirectory will be created to show a full history of configuration that was used for this service.
ConfigMaps that are mounted into the pod that describes this service will be created relative to these run directories - unless the mounts specify an absolute path, in which case it is allowed to break out of this directory.

The agent will need full access to this directory and tries to create it if it does not exist.


### no-config

*Default value*: No default value

*Required*: false

*Multiple values:*: false


If this option is specified, any file referenced in AGENT_CONF environment variable will be ignored.


### server-bind-ip

*Default value*: No default value

*Required*: false

*Multiple values:*: false


The local IP to register as the node's ip with the apiserver. Will be automatically set to the first address of the first non-loopback interface if not specified.


### tag

*Default value*: No default value

*Required*: false

*Multiple values:*: true


Tags are the main way of identifying nodes to assign services to later on.


### server-cert-file

*Default value*: No default value

*Required*: false

*Multiple values:*: false


The certificate file for the local webserver which the Krustlet starts.


### server-key-file

*Default value*: No default value

*Required*: false

*Multiple values:*: false


Private key file (in PKCS8 format) to use for the local webserver the Krustlet starts.


### package-directory

*Default value*: /opt/stackable/packages

*Required*: false

*Multiple values:*: false


This directory will serve as starting point for packages that are needed by pods assigned to this node.
Packages will be downloaded into the "_download" folder at thetop level of this folder as archives and remain there for potential future use.
Archives will the be extracted directly into this folder in subdirectories following the namingscheme of "productname-productversion".
The agent will need full access to this directory and tries to create it if it does not exist.


### log-directory

*Default value*: /opt/stackable/logs

*Required*: false

*Multiple values:*: false


This directory will serve as starting point for all log files which this service creates.Every service will get its own subdirectory created within this directory.
Anything that is then specified in the log4j config or similar files will be resolved relatively to this directory.

The agent will need full access to this directory and tries to create it if it does not exist.
51 changes: 45 additions & 6 deletions src/agentconfig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,10 @@ impl AgentConfig {
takes_argument: true,
help: "The base directory under which installed packages will be stored.",
documentation: "This directory will serve as starting point for packages that are needed by \
pods assigned to this node.\n Packages will be downloaded into the \"_download\" folder at the
top level of this folder as archives and remain there for potential future use.\n\
Archives will the be extracted directly into this folder in subdirectories following the naming
scheme of \"productname-productversion\".
pods assigned to this node.\n Packages will be downloaded into the \"_download\" folder at the\
top level of this folder as archives and remain there for potential future use.\n\
Archives will the be extracted directly into this folder in subdirectories following the naming\
scheme of \"productname-productversion\".
The agent will need full access to this directory and tries to create it if it does not exist.",
list: false,
};
Expand All @@ -83,7 +83,7 @@ scheme of \"productname-productversion\".
help: "The base directory under which configuration will be generated for all executed services.",
documentation: "This directory will serve as starting point for all log files which this service creates.\
Every service will get its own subdirectories created within this directory - for every service start a \
new subdirectory will be created to show a full history of configuration that was used for this service.\n
new subdirectory will be created to show a full history of configuration that was used for this service.\n\
ConfigMaps that are mounted into the pod that describes this service will be created relative to these run \
directories - unless the mounts specify an absolute path, in which case it is allowed to break out of this directory.\n\n\
The agent will need full access to this directory and tries to create it if it does not exist.",
Expand All @@ -97,7 +97,7 @@ scheme of \"productname-productversion\".
takes_argument: true,
help: "The base directory under which log files will be placed for all services.",
documentation: "This directory will serve as starting point for all log files which this service creates.\
Every service will get its own subdirectory created within this directory.\n
Every service will get its own subdirectory created within this directory.\n\
Anything that is then specified in the log4j config or similar files will be resolved relatively to this directory.\n\n\
The agent will need full access to this directory and tries to create it if it does not exist.",
list: false,
Expand Down Expand Up @@ -201,10 +201,49 @@ scheme of \"productname-productversion\".
};
None
}

pub fn get_documentation() -> Result<String, AgentConfigError> {
let mut doc_string = String::new();
for option in AgentConfig::get_options() {
doc_string.push_str(&format!("\n\n\n### {}\n\n", option.name));
doc_string.push_str(&format!(
"*Default value*: {}\n\n",
option.default.unwrap_or("No default value")
));
doc_string.push_str(&format!("*Required*: {}\n\n", option.required));
doc_string.push_str(&format!("*Multiple values:*: {}\n\n\n", option.list));

// We have not yet specified a documentation string for all options, as an interim
// solution we use the help string for the docs, if no proper doc has been written yet.
if option.documentation.is_empty() {
doc_string.push_str(&option.help);
} else {
doc_string.push_str(&option.documentation);
}
}
Ok(doc_string)
}

fn gen_docs() {
// TODO: this needs to be moved to a build.rs type of thing
use std::env;
use std::fs;
use std::path::PathBuf;

let target_file = PathBuf::from("config/commandline_args.adoc");

// We have unwraps in here, as this is supposed to be called during the build process,
// it shouldn't even be part of the codebase itself.
// Once this is moved out the unwraps are fine, because a failure during build is ok if
// something is wrong.
let test = AgentConfig::get_documentation().unwrap();
fs::write(&target_file, test).unwrap();
}
}

impl Configurable for AgentConfig {
fn get_config_description() -> Configuration {
AgentConfig::gen_docs();
Configuration {
name: "Stackable Agent",
version: "0.1",
Expand Down