惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Security @ Cisco Blogs
H
Hacker News: Front Page
P
Privacy International News Feed
N
News and Events Feed by Topic
T
Threatpost
Simon Willison's Weblog
Simon Willison's Weblog
S
Schneier on Security
K
Kaspersky official blog
S
Secure Thoughts
V2EX - 技术
V2EX - 技术
Security Latest
Security Latest
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
www.infosecurity-magazine.com
www.infosecurity-magazine.com
C
CERT Recently Published Vulnerability Notes
L
Lohrmann on Cybersecurity
Jina AI
Jina AI
P
Proofpoint News Feed
AI
AI
雷峰网
雷峰网
T
Tailwind CSS Blog
Engineering at Meta
Engineering at Meta
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Recent Commits to openclaw:main
Recent Commits to openclaw:main
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
博客园 - 叶小钗
Webroot Blog
Webroot Blog
Apple Machine Learning Research
Apple Machine Learning Research
SecWiki News
SecWiki News
罗磊的独立博客
N
Netflix TechBlog - Medium
Martin Fowler
Martin Fowler
Google DeepMind News
Google DeepMind News
Cyberwarzone
Cyberwarzone
MongoDB | Blog
MongoDB | Blog
博客园 - Franky
Schneier on Security
Schneier on Security
The GitHub Blog
The GitHub Blog
S
Security Affairs
Blog — PlanetScale
Blog — PlanetScale
Last Week in AI
Last Week in AI
P
Proofpoint News Feed
月光博客
月光博客
D
Docker
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
S
Securelist
W
WeLiveSecurity
T
Troy Hunt's Blog
A
Arctic Wolf
博客园 - 司徒正美

Martin Heinz's Blog

A Guide to Python's Weak References Using weakref Module Recent Docker BuildKit Features You're Missing Out On Modern Git Commands and Features You Should Be Using Everything You Can Do with Python's textwrap Module Monitoring Indoor Air Quality with Prometheus, Grafana and a CO2 Sensor Everything You Can Do with Python's bisect Module You Don't Need a Dedicated Cache Service - PostgreSQL as a Cache A Collection of Docker Images To Solve All Your Debugging Needs Weird Python "Features" That Might Catch You By Surprise Lessons Learned From Writing 100 Articles Debugging Crashes and Deadlocks in Python using PyStack Goodbye etcd, Hello PostgreSQL: Running Kubernetes with an SQL Database Remote Interactive Debugging of Python Applications Running in Kubernetes The Right Way to Run Shell Commands From Python Real Multithreading is Coming to Python - Learn How You Can Use It Now Python's Missing Batteries: Essential Libraries You're Missing Out On Kubernetes-Native Synthetic Monitoring with Kuberhealthy Make Your CLI Demos a Breeze with Zero Stress and Zero Mistakes Reduce - The Power of a Single Python Function Why I Will Never Use Alpine Linux Ever Again Cgroups - Deep Dive into Resource Management in Kubernetes Dictionary Dispatch Pattern in Python Boost Your Python Application Performance using Continuous Profiling Lazy Evaluation Using Recursive Python Generators Python Magic Methods You Haven't Heard About Getting Started with Mastodon API in Python Getting Started with Google APIs in Python Python CLI Tricks That Don't Require Any Code Whatsoever All The Ways To Introspect Python Objects at Runtime What is Python's "self" Argument, Anyway? Python List Comprehensions Are More Powerful Than You Might Think You Should Be Using Python's Walrus Operator - Here's Why Recipes and Tricks for Effective Structural Pattern Matching in Python It's Time to Say Goodbye to These Obsolete Python Libraries Advanced Features of Kubernetes' Horizontal Pod Autoscaler Data and System Visualization Tools That Will Boost Your Productivity Stop Messing with Kubernetes Finalizers Automate All the Boring Kubernetes Operations with Python End-to-End Monitoring with Grafana Cloud with Minimal Effort Bitly | bit.ly/3JLmSgA Bitly | bit.ly/3uETfbi Bitly | bit.ly/3MI4Iz0 Bitly | bit.ly/3M30D82 Bitly | bit.ly/3oMJ6qR Bitly | bit.ly/3IRD7IK Bitly | bit.ly/3A3B69t Bitly | bit.ly/31lKCYA Bitly | bit.ly/30uviIM Bitly | bit.ly/3E1X2mw Bitly | bit.ly/3Dv7JxP Bitly | bit.ly/3GG1BEz Bitly | bit.ly/3lLavs4 Bitly | bit.ly/39TqP3m Bitly | bit.ly/3A5Mpx8 Bitly | bit.ly/3kGwPl4 Bitly | bit.ly/3iHtulU Bitly | bit.ly/3xGjtKS Bitly | bit.ly/3h8DZg0 Bitly | bit.ly/2RQn1dG Bitly | bit.ly/3p2B5wW The Easiest Way to Debug Kubernetes Workloads Bitly | bit.ly/2PHVudx Cloud Native CI/CD with Tekton - Building Custom Tasks Bitly | bit.ly/3dg3QR9 Bitly | bit.ly/3qHtSkZ Deep Dive into Docker Internals - Union Filesystem Bitly | bit.ly/3qlRAUN Bitly | bit.ly/3pCUJ26 Bitly | bit.ly/3ifZxYr Bitly | bit.ly/34ZhIMt Bitly | bit.ly/3qSO7h0 Bitly | bit.ly/3muGLOk Bitly | bit.ly/35xN79v Bitly | bit.ly/3mLGshK Bitly | bit.ly/2IvkGQl Bitly | bit.ly/2Sk1KFK Bitly | bit.ly/3iCNIL6 Bitly | bit.ly/3beQPpy Saving Your Linux Machine from Certain Death New Features in Python 3.9 You Should Know About Deploy Any Python Project to Kubernetes Analyzing Docker Image Security Recursive SQL Queries with PostgreSQL Automating Every Aspect of Your Python Project Tour of Python Itertools Implementing 2D Physics in Javascript Ultimate Setup for Your Next Python Project Making Python Programs Blazingly Fast Security and Cryptography Mistakes You Are Probably Doing All The Time Going Serverless with OpenFaaS and Golang - Building Optimized Templates Going Serverless with OpenFaaS and Golang - The Ultimate Setup and Workflow Setting Up Swagger Docs for Golang API Building RESTful APIs in Golang Pytest Features, That You Need in Your (Testing) Life Setting up GitHub Package Registry with Docker and Golang Ultimate Setup for Your Next Golang Project Python Tips and Trick, You Haven't Already Seen, Part 2. Tricks for Postgres and Docker that will make your life easier Getting The Most Out of Reading Books - Reading The "Professional Way" Python Tips and Trick, You Haven't Already Seen
Backup-and-Restore of Containers with Kubernetes Checkpointing API
Martin · 2022-11-16 · via Martin Heinz's Blog

Kubernetes v1.25 introduced Container Checkpointing API as an alpha feature. This provides a way to backup-and-restore containers running in Pods, without ever stopping them.

This feature is primarily aimed at forensic analysis, but general backup-and-restore is something any Kubernetes user can take advantage of.

So, let's take a look at this brand-new feature and see how we can enable it in our clusters and leverage it for backup-and-restore or forensic analysis.

Setup

Before we start checkpointing any containers, we need a playground where we can mess with kubelet and its workloads. For that we will need a v1.25+ Kubernetes cluster and container runtime that supports container checkpointing.

We will create such cluster using kubeadm inside VM(s) built with Vagrant. I've created repository with everything necessary to spin up such cluster with just vagrant up, so if you want to follow along, do check it out.

If you want to build your own cluster, then make sure it satisfies the following:

The cluster must have ContainerCheckpoint feature flag enabled. For kubeadm use following configuration:


# kubeadm-config.yaml
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
featureGates:
  ContainerCheckpoint: true
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: v1.25.0
apiServer:
  extraArgs:
    feature-gates: "ContainerCheckpoint=true"
controllerManager:
  extraArgs:
    feature-gates: "ContainerCheckpoint=true"
scheduler:
  extraArgs:
    feature-gates: "ContainerCheckpoint=true"
networking:
  podSubnet: 10.244.0.0/16

This will pass the --feature-gates flag to each of the cluster components. For full list of available feature gates see docs.

Additionally, we will also need to use a container runtime that supports checkpointing. At the time of writing only CRI-O supports it, with containerd probably coming soon-ish.

To configure your cluster with CRI-O, install it using instructions in docs, or use the convenience script in above-mentioned repository (you should run this in VM, not on your local machine).

Additionally, we need to enable CRIU for CRI-O, which is the tool that does the actual checkpointing in the background.

To enable it, we need to set --enable-criu-support=true flag. The above convenience script does that for you.

Also, if you plan to restore it back into a Pod, you will also need --drop-infra-ctr set to false, otherwise you will get CreateContainerError with message like:


kubelet  Error: pod level PID namespace requested for the container, ...
... but pod sandbox was not similarly configured, and does not have an infra container

With CRI-O installed, we also have to tell kubeadm to use its socket, the following configuration with take care of that:


# kubeadm-config.yaml
apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
localAPIEndpoint:
  advertiseAddress: 192.168.56.2
  bindPort: 6443
nodeRegistration:
  criSocket: "unix:///var/run/crio/crio.sock"
---
# ... the previous snippet goes here
# Full config at:
# https://github.com/MartinHeinz/kubeadm-vagrant-playground/blob/container-checkpoint-api/kubernetes/kubeadm-config.yaml

With that in place we can spin-up cluster with:


kubeadm init --config=.../kubeadm-config.yaml --upload-certs | tee kubeadm-init.out

This should give us a single node cluster such as (note the container runtime version):


kubectl get nodes -o wide
NAME         STATUS   ROLES           AGE   VERSION  ...  OS-IMAGE             KERNEL-VERSION      CONTAINER-RUNTIME
kubemaster   Ready    control-plane   82s   v1.25.4  ...  Ubuntu 20.04.5 LTS   5.4.0-125-generic   cri-o://1.25.0

Note: Generally, the best and simplest way to play with Kubernetes is using KinD. KinD however (as of time of writing) doesn't support container checkpointing. Alternatively you can also try local-up-cluster.sh script in Kubernetes repository.

Checkpointing

With that out of the way, we can try creating a checkpoint. The usual operations on Kubernetes can be done with kubectl or by running curl commands against cluster API server. This however won't work here, as the checkpointing API is only exposed on the kubelet on each cluster node.

Therefore, we have to jump onto the node and talk to kubelet directly:


vagrant ssh kubemaster
sudo su -

# Check if it's running...
systemctl status kubelet

kubelet.service - kubelet: The Kubernetes Node Agent
   Loaded: loaded (/lib/systemd/system/kubelet.service; enabled; vendor preset: enabled)
  Drop-In: /etc/systemd/system/kubelet.service.d
           └─10-kubeadm.conf
   Active: active (running) since Sat 2022-11-12 10:25:29 UTC; 30s ago
     Docs: https://kubernetes.io/docs/home/
 Main PID: 29501 (kubelet)
    Tasks: 14 (limit: 2339)
   Memory: 34.7M
   CGroup: /system.slice/kubelet.service
           └─29501 /usr/bin/kubelet --bootstrap-kubeconfig=... --kubeconfig=...

To create checkpoint we also need a running Pod. Rather than using system Pods in kube-system, let's create a dummy Nginx webserver in default namespace:


kubectl taint nodes --all node-role.kubernetes.io/control-plane-
kubectl run webserver --image=nginx -n default
kubectl get pods -o wide
NAME        READY   STATUS    RESTARTS   AGE   IP          NODE
webserver   1/1     Running   0          27s   10.85.0.4   kubemaster

Above you can see that we also removed taints from the node - this allows us to schedule workloads on the node even though it's part of control-plane.

Next, let's make a sample API request to kubelet to see if we can get any valid response:


curl -skv -X GET  "https://localhost:10250/pods" \
  --key /etc/kubernetes/pki/apiserver-kubelet-client.key \
  --cacert /etc/kubernetes/pki/ca.crt \
  --cert /etc/kubernetes/pki/apiserver-kubelet-client.crt

{
  "kind": "PodList",
  "apiVersion": "v1",
  "metadata": {},
  "items": [
    {
      "metadata": {
        "name": "webserver",
        "namespace": "default",
        ...
        }
    }
    ...
}

kubelet by default runs on port 10250, so we curl it and ask for all its Pods. We also had to specify CA certificate, client certificate and key for authentication.

Now it's time to finally create a checkpoint:


curl -sk -X POST  "https://localhost:10250/checkpoint/default/webserver/webserver" \
  --key /etc/kubernetes/pki/apiserver-kubelet-client.key \
  --cacert /etc/kubernetes/pki/ca.crt \
  --cert /etc/kubernetes/pki/apiserver-kubelet-client.crt

# Response:
# {"items":["/var/lib/kubelet/checkpoints/checkpoint-webserver_default-webserver-2022-11-12T10:28:13Z.tar"]}

# Check the directory:
ls -l /var/lib/kubelet/checkpoints/

total 3840
-rw------- 1 root root 3931136 Nov 12 10:28 checkpoint-webserver_default-webserver-2022-11-12T10:28:13Z.tar

# Verify that original container is still running:
crictl ps --name webserver
CONTAINER      IMAGE                               CREATED         STATE    NAME       ATTEMPT  POD ID         POD
880ee7ddff7f3  docker.io/library/nginx@sha256:...  48 seconds ago  Running  webserver  0        d584446dd8d5e  webserver

The checkpointing API is available at .../checkpoint/${NAMESPACE}/${POD}/${CONTAINER}, here we used the webserver Pod created earlier. This request created an archive in /var/lib/kubelet/checkpoints/checkpoint-<pod>_<namespace>-<container>-<timestamp>.tar.

Depending on the setup you're using, after running the above curl, you might receive error along the lines:


checkpointing of default/webserver/webserver failed (CheckpointContainer is only supported in the CRI v1 runtime API)
# or
checkpointing of default/webserver/webserver failed (rpc error: code = Unknown desc = checkpoint/restore support not available)

That means that your container runtime doesn't (yet) support checkpointing, or it's not enabled correctly.

Analyzing

We now have a checkpointed container archive, so let's take a look at what's inside:


cd /var/lib/kubelet/checkpoints/
# Rename because "tar" doesn't like ":" in names
mv "checkpoint-webserver_default-webserver-2022-11-12T10:28:13Z.tar" webserver.tar
# View contents:
tar --exclude="*/*" -tf webserver.tar

dump.log
checkpoint/
config.dump
spec.dump
rootfs-diff.tar
io.kubernetes.cri-o.LogPath

# Extract:
tar -xf checkpoint-webserver_default-webserver-2022-09-04T10:15:37Z.tar
ls checkpoint/
cgroup.img        fdinfo-4.img  ids-31.img        mountpoints-13.img       pages-2.img               tmpfs-dev-139.tar.gz.img
core-1.img        files.img     inventory.img     netns-10.img             pages-3.img               tmpfs-dev-140.tar.gz.img
core-30.img       fs-1.img      ipcns-var-11.img  pagemap-1.img            pages-4.img               tmpfs-dev-141.tar.gz.img
core-31.img       fs-30.img     memfd.img         pagemap-30.img           pstree.img                tmpfs-dev-142.tar.gz.img
descriptors.json  fs-31.img     mm-1.img          pagemap-31.img           seccomp.img               utsns-12.img
fdinfo-2.img      ids-1.img     mm-30.img         pagemap-shmem-94060.img  timens-0.img
fdinfo-3.img      ids-30.img    mm-31.img         pages-1.img              tmpfs-dev-136.tar.gz.img


cat config.dump
{
  "id": "880ee7ddff7f3ce11ee891bd89f8a7356c97b23eb44e0f4fbb51cb7b94ead540",
  "name": "k8s_webserver_webserver_default_91ad1757-424e-4195-9f73-349b332cbb7a_0",
  "rootfsImageName": "docker.io/library/nginx:latest",
  "runtime": "runc",
  "createdTime": "2022-11-12T10:27:56.460946241Z"
}

tar -tf rootfs-diff.tar
var/cache/nginx/proxy_temp/
var/cache/nginx/scgi_temp/
var/cache/nginx/uwsgi_temp/
var/cache/nginx/client_temp/
var/cache/nginx/fastcgi_temp/
etc/mtab
run/nginx.pid
run/secrets/kubernetes.io/
run/secrets/kubernetes.io/serviceaccount/

If you don't need a running Pod/container for analysis, then extracting and reading through some of the above shown files might give you the necessary information.

With that said, I'm no security expert, so I'm not going to feed you questionable information here about how to analyze these files.

As a starting point though, you might want check out tools like docker-explorer or this talk on container forensics in Kubernetes.

Restoring

While the Checkpointing API is currently aimed more at forensic analysis, it still can be used to restore the Pod/container from the archive.

The simplest way is to create an image from checkpoint archive:


FROM scratch
# Need to use ADD because it extracts archives
ADD webserver.tar .

Here we use an empty (scratch) image to which we add the archive. We need to use ADD because it automatically extracts archives. Next, we build it with docker or buildah:


cd /var/lib/kubelet/checkpoints/
# Or docker build ...
buildah bud \
  --annotation=io.kubernetes.cri-o.annotations.checkpoint.name=webserver \
  -t restore-webserver:latest \
  Dockerfile .

buildah push localhost/restore-webserver:latest docker.io/martinheinz/restore-webserver:latest

Above we also specify annotation which describes the original human-readable name of the container and then we push to some registry so that Kubernetes can pull it.

Finally, we create a Pod, specifying the previously pushed image:


# pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: restore-webserver
  labels:
    app: nginx
spec:
  containers:
  - name: webserver
    image: docker.io/martinheinz/restore-webserver:latest
  nodeName: kubemaster

To test if it worked, we can expose the Pod via Service and curl its IP:


kubectl expose pod restore-webserver --port=80 --target-port=80
kubectl get svc

NAME                TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
kubernetes          ClusterIP   10.96.0.1      <none>        443/TCP   14m
restore-webserver   ClusterIP   10.104.30.90   <none>        80/TCP    17s

curl http://10.104.30.90

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
</html>

And it worked! We successfully backed-up a running Pod without stopping it and recreated it to its original state.

Closing Thoughts

General checkpoint-and-restore for containers has been possible for a while thanks to CRIU, but this is still a big step for Kubernetes, and hopefully, we will see this feature/API graduate to Beta and eventually GA at some point.

The previous sections demonstrated the usage of checkpointing API - it's very much usable, but it also lacks some basic features, such as native restore functionality or support from all major container runtimes. So, be aware of its limitations if you decide to enable it in production (or even development) environments/clusters.

With that said, this feature is very cool addition not just for forensic analysis - in the future when better/native restore process is available, this could become a proper backup-and-restore process for container workloads, which might be very useful for certain types of long-running Kubernetes workloads.