MyGit

v0.5.0

krustlet/krustlet

版本发布时间: 2020-09-23 02:33:04

krustlet/krustlet最新发布版本:v1.0.0-alpha.1(2021-07-28 01:06:02)

Krustlet v0.5.0 is mostly an "under the hood" release if you are just a consumer of Krustlet, although there still are a few useful feature adds! However, if you are using the kubelet crate, there have been significant API changes that lay the groundwork for solid features in the future. These changes are explained below. For more details on what isn't implemented yet, see the Known Issues section.

Because this is pre-release software, there are no backwards compatibility guarantees for the Rust API or functionality. However, we will do our best to document any breaking changes in future releases.

Caveats

Please note that this is NOT production-ready software, but it is in a usable state. The WASI standard and wasmtime are still under heavy development, and because of this there are key features (like networking) that are missing; these will appear in the future. However, there is networking support available in wasCC.

Notable Features/Changes

Breaking changes

Due to the requirements in Kubernetes 1.19, Krustlet no longer can self label its node object with a role. Full details about why this change was needed can be found here. In practice, this means your node selectors on Pods meant to be run on a Krustlet node should not rely on the role. It is a little unclear what is the best practice here from the Kubernetes standpoint (automation after node joining or some other sort of reconciliation process), but in our experience we find it best to select on the architecture like so:

nodeSelector:
    beta.kubernetes.io/os: linux
    beta.kubernetes.io/arch: wasm32-wascc

You can see various examples of selectors in our demos.

New Provider API and State Machine

This section details the major changes to the kubelet crate API. If you do not consume this crate or write your own provider, feel free to skip to the next section.

First and foremost, the Provider trait has been hugely slimmed down. The current trait (with new members commented) as of publishing time is:

pub trait Provider: Sized {
    /// The state that is passed between Pod state handlers.
    type PodState: 'static + Send + Sync + AsyncDrop;

    /// The initial state for Pod state machine.
    type InitialState: Default + State<Self::PodState>;

    /// The a state to handle early Pod termination.
    type TerminatedState: Default + State<Self::PodState>;

    const ARCH: &'static str;

    async fn node(&self, _builder: &mut Builder) -> anyhow::Result<()> {
        Ok(())
    }

    /// Hook to allow provider to introduced shared state into Pod state.
    async fn initialize_pod_state(&self, pod: &Pod) -> anyhow::Result<Self::PodState>;

    async fn logs(
        &self,
        namespace: String,
        pod: String,
        container: String,
        sender: Sender,
    ) -> anyhow::Result<()>;

    async fn exec(&self, _pod: Pod, _command: String) -> anyhow::Result<Vec<String>> {
        Err(NotImplementedError.into())
    }

    async fn env_vars(
        container: &Container,
        pod: &Pod,
        client: &kube::Client,
    ) -> HashMap<String, String> {
        ...
    }
}

We have removed all of the separate functions for handling the basic CRUD operations as those are now handled by the new state machine (covered below). A few important details about the new parts of the Provider: The InitialState and TerminatedState allow Provider authors to specify what the starting state for a Pod is and the state it should jump to if deleted. The PodState and initialize_pod_state are used in conjunction to allow your Provider to exposed shared state (often stored within the Provider itself) to all of the pods. A simple example of this is the set of currently assigned ports used in the waSCC provider. This shared state must implement the custom AsyncDrop as Rust currently has no async drop standard.

In this new paradigm, providers are expected to provide a full state machine for the lifecycle of the pod. This new design allows for each step of processing to be encapsulated in its own state (e.g. pulling images is one state, starting containers is another). At the heart of this is one new trait, State, and one new enum: Transition as shown below:

pub trait State<PodState>: Sync + Send + 'static + std::fmt::Debug {
    /// Provider supplies method to be executed when in this state.
    async fn next(
        self: Box<Self>,
        pod_state: &mut PodState,
        pod: &Pod,
    ) -> anyhow::Result<Transition<PodState>>;

    /// Provider supplies JSON status patch to apply when entering this state.
    async fn json_status(
        &self,
        pod_state: &mut PodState,
        pod: &Pod,
    ) -> anyhow::Result<serde_json::Value>;
}
pub enum Transition<PodState> {
    /// Transition to new state.
    Next(StateHolder<PodState>),
    /// This is a terminal node of the state graph.
    Complete(anyhow::Result<()>),
}

Each state in your machine must implement the State trait. The json_status function is called when entering into the state to update the status in Kubernetes. The next function is called in an iterative fashion to walk through the state machine. Transitions to other states are done using the Transition next method, which abstracts away some boxing and other things behind the scenes to construct a Transition::Next.

For additional safety, each state must explicitly mark what its next possible states are using the TransitionTo trait, providing compile time guarantees that you aren't transitioning into a state you aren't expecting.

To tie it all together, here is a super simple implementation of a state:

use kubelet::state::{Transition, State, TransitionTo};
use kubelet::pod::Pod;

#[derive(Debug)]
struct TestState;

impl TransitionTo<TestState> for TestState {}

struct PodState;

#[async_trait::async_trait]
impl State<PodState> for TestState {
    async fn next(
        self: Box<Self>,
        _pod_state: &mut PodState,
        _pod: &Pod,
    ) -> anyhow::Result<Transition<PodState>> {
        Ok(Transition::next(self, TestState))
    }

    async fn json_status(
        &self,
        _pod_state: &mut PodState,
        _pod: &Pod,
    ) -> anyhow::Result<serde_json::Value> {
        Ok(serde_json::json!(null))
    }
}

If you are interested in the technical details and design decisions behind the state machine, there will be a forthcoming blog post on https://deislabs.io (we will update the link here when it releases). Please note that this API is still needs some polishing work. We don't expect any more major changes like what is in this release, but there will be various ergonomic changes to make it easier to use as we continue to iterate.

For real world examples of a provider implementation, please take a look at the WASI and waSCC providers in Krustlet. See the crate documentation for full documentation and more examples.

Known Issues/Missing Features

What's next?

Our next anticipated version is 0.6.0 (although we will cut a 0.5.1 if necessary). You can see a full list of issues planned for 0.6 in the milestone. Our main focus for 0.6 will be around supporting cloud provider volumes and continued API ergonomic enhancements. During the next release cycle, we will also be moving out the waSCC provider to its own repo. Full details will be in the 0.6 release notes.

Thanks

We want to express a huge thanks to all of those in the community who contributed to this release. We appreciate your efforts in making this project a success.

We also would like to call out @kflansburg's herculean efforts with the new state machine API and refactor. He recently joined us as a core maintainer and took the lead on this massive chunk of work. If you see him on the interwebs, please say thanks!

Contributors to 0.5

Installation

Download Krustlet 0.5.0:

Check out our installation docs for information on how to install Krustlet.

相关地址:原始地址 下载(tar) 下载(zip)

查看:2020-09-23发行的版本