0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Docker/Kubernetesをつなぐコンテナランタイム「Raind」

0
Posted at

はじめに

筆者が開発を続けているRaindという自作コンテナランタイムについて紹介しようと思います。

GitHub Repoはこちら: https://github.com/shizuku198411/Raind

筆者自身は数年前からコンテナランタイムを開発しており、最初はコンテナの仕組みを知るために始めたのですが、コンテナランタイムの仕組みは非常に奥深く、何度も様々な言語/仕組みでランタイムを開発していました。
もちろんランタイム開発だけではなく日常的にDocker/Kubernetesといったコンテナ基盤を活用しています。
コンテナランタイムを開発しながら成熟した2つの仕組みを利用していると、既存の仕組みの便利さにも気づきますが、もう少しこうしたい!というものも出てくるものです。

DockerにはDockerの扱いやすさがあります。
一方でKubernetesにはPod/Service/Ingressのような、アプリケーションをworkloadとして扱うための強いモデルがあります。

ただ、この2つは普段かなり別の世界として扱われます。

  • Docker 的に単体コンテナを起動する
  • Kubernetes 的に Pod / Deployment / Service / Ingress としてデプロイする
  • 通信制御やトラフィック可視化を runtime レベルで扱う

こういうものを、できるだけ1つのランタイムの中で扱えるようにしたいと考えるようになりました。
その方向で作っているのがRaindです。

この記事では、Raindがどういうランタイムなのか、どういう意図で拡張してきたのか、実際にどう使えるのかを、開発記録としてまとめます。

Raindとは

Raindは、ざっくり言うと Docker/Kubernetes の Container/Pod を統合的に扱うためのコンテナランタイムです。

単体コンテナを起動するだけではなく、Pod、Deployment、Service、Ingress、通信ポリシー、ネットワーク可視化までを、1つの runtime stack として扱うことを目指しています。

内部的には、大きく次のような構成です。

+-------+        +-----------+        +---------+
| raind | -----> | condenser | -----> | droplet |
+-------+        +-----------+        +---------+
   CLI          high-level runtime    low-level runtime
  • raind: CLI
  • condenser: API / controller / resource 管理 / network / policy / ingress などを扱う high-level runtime
  • droplet: namespace / cgroup / mount / pivot_root などを扱う low-level container runtime

Docker 的な container run もできます。

raind container run --name web -p 8080:80 nginx:latest

一方で、Kubernetes-styleのYAMLを resource apply して、Deployment/Service/Ingress まで作ることもできます。

raind resource apply -f manifest.yaml

Raindがやりたいのは、Kubernetes を完全に再実装することではなく、
Kubernetes-styleな考え方を取り込みつつ、単体コンテナ・Pod・Service・Ingress・通信制御・可視化を、1つのランタイムの中で扱えるようにすることです。

開発意図

Docker 的な扱いやすさと Kubernetes 的な構造をまとめたい

Docker は単体コンテナを動かす体験がかなり良いです。

docker run nginx

みたいな感覚で、すぐにコンテナを起動できます。
一方で、アプリケーションを少し大きい単位で見ると、PodやServiceやIngressのようなモデルがほしくなります。

例えば、アプリケーションをデプロイする場合は、アプリ本体だけではなくアプリへのアクセス経路も構築したくなります。

app
  ├── Pod
  │   └── containers
  ├── Service
  │   └── stable L4 endpoint
  └── Ingress
      └── host/path based routing

Kubernetesではこれらがかなりよく整理されているので、このような場合はDockerではなくKubernetesを利用することが一般的です。

ただ、Kubernetesは本格的な構成でもあるため、
ちょっとPodとしてアプリを起動したい、ServiceとIngressの流れを確認したい、というためにKubernetesを構築するのは少し手間がかかります。

単体コンテナはDocker Likeに扱える。
でも、必要になったら Pod/Deployment/Service/IngressのようなKubernetes-styleのリソースも同じランタイムで扱える。

この「DockerとKubernetesの間の距離を縮める」ようなランタイムを作りたい、というのが Raindの大きな方針です。

通信制御・可視化を runtime レベルで組み込みたい

もう1つやりたかったのが、通信制御や可視化をランタイムレベルで組み込むことです。

DockerやKubernetesでもネットワーク制御の仕組みはあります。
ただ、自分が作りたかったのは、コンテナやPodの通信をランタイム自体が把握していて、通信ログやポリシーと自然につながる形です。

Raindでは、通信を大きく2つに分けています。

East-West
  コンテナ間 / Pod 間の内部通信

North-South
  コンテナや Pod から外部への通信

現状の方針としては、次のようにしています。

  • コンテナ間通信は default deny
  • 外部通信は default allow / observe
  • 必要な内部通信だけ policy で許可する
  • 通信ログでは、可能な限り IP ではなく container 名に戻して表示する

コンテナ間通信をdefault denyにしているのは、内部通信を明示的に許可する形にしたかったからです。
逆に外部通信は、最初から全部止めると扱いづらいので、まずは observe しながら許可する形にしています。
ここはZero Trust Networkをコンテナランタイムに落とし込んでみる、という意図もあります。
昨今コンテナも必ずしも安全な環境ではなくなりつつあり、サプライチェーン攻撃等による不審な通信などもしっかりと把握する必要があるためです。

利用イメージ

Raind では、大きく次のような使い方を想定しています。

Raind
  ├── Single Container
  ├── Bottle
  ├── Resources
  │   ├── Pod
  │   ├── ReplicaSet
  │   ├── Deployment
  │   ├── Service
  │   └── Ingress
  └── Traffic Observability & Control

Single Container: Docker Like

一番シンプルなのは、Dockerのように単体コンテナを起動する使い方です。

raind container run --name web -p 8080:80 nginx:latest

この場合はDockerと同じく、イメージをpullして、rootfsを展開し、namespace/cgroup/mountを構成して、コンテナを起動します。

単体コンテナとして起動したい場合は、この使い方が一番シンプルです。

Bottle: Docker Compose Like

Raind にはBottleという単位もあります。
これはDocker Compose的に、複数のコンテナをまとめて扱うための仕組みです。

Docker Composeとほぼ同等のYAMLで定義が可能です。

bottle:
  name: wordpress

services:
  wp:
    image: wordpress:latest
    env:
      - WORDPRESS_DB_HOST=db:3306
      - WORDPRESS_DB_USER=wordpress
      - WORDPRESS_DB_PASSWORD=wordpress
      - WORDPRESS_DB_NAME=wordpress
    ports:
      - "11240:80"
    capAdd:
      - CAP_NET_BIND_SERVICE
    depends_on:
      - db

  db:
    image: mysql:latest
    env:
      - MYSQL_ROOT_PASSWORD=wordpress
      - MYSQL_DATABASE=wordpress
      - MYSQL_USER=wordpress
      - MYSQL_PASSWORD=wordpress

policies:
  - type: east-west
    source: wp
    destination: db
    protocol: tcp
    dest_port: 3306
    comment: "wp -> db 3306/tcp"

単体コンテナより少し大きい単位で、関連するコンテナ群をまとめて起動・管理したいときに使うイメージです。

さらに、冒頭でも記載したとおり通信制御を定義することができます。
少々面倒に思えますが、アプリケーションとして本当に必要な通信のみを許可することで
セキュリティ向上にも通信要件の整理にもつながります。

Resources: Kubernetes Like

Raind ではKubernetes-styleのmanifestをデプロイできます。
ここでは実際の例を1つ載せます。

次のmanifestでは、Namespace、Deployment、Service、Ingressを定義しています。

apiVersion: v1
kind: Namespace
metadata:
  name: demo
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo-web
  namespace: demo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: demo-web
  template:
    metadata:
      labels:
        app: demo-web
    spec:
      containers:
        - name: web
          image: nginx:latest
          ports:
            - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: demo-svc
  namespace: demo
spec:
  selector:
    app: demo-web
  ports:
    - port: 80
      targetPort: 80
      protocol: TCP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: demo-ingress
  namespace: demo
spec:
  tls:
    - hosts:
        - demo.local
  rules:
    - host: demo.local
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: demo-svc
                port:
                  number: 80

manifestに関してはkubernetesとの互換性を意識しているため、上記のmanifestはkuberenetesでも同様にデプロイできるものです。
適用すると、Namespace用のネットワークが作られ、Deployment/Service/Ingressが作成されます。

$ raind resource apply -f manifest.yaml
namespace: demo applied (network: rns2a97516c354b)
deployment: 01kv2x6ft6183we8g2e696z3ad applied
service: 01kv2x6ftbetxc6dp5r7cr337t applied
ingress: 01kv2x6h2vmysh72jeff7mz2ph applied (tls: enabled, hosts: demo.local)

各リソースの確認は以下のようになります。

# Deployment
$ raind resource deploy ls -n demo
DEPLOYMENT ID               NAME      NAMESPACE  DESIRED  CURRENT  READY  REPLICASET                  CREATED
01kv2x6ft6183we8g2e696z3ad  demo-web  demo       2        2        2      01kv2x6hbvr3c4sqx476k7sjsm  less than a minutes

REPLICASETが表示されている通り、RaindでもPod数を維持するためのReplicaSet的な仕組みを持っています。

# pod
$ raind resource pod ls -n demo
POD ID                      NAME               NAMESPACE  UID  READY    STATE  CREATED
01kv2x6hc74yxrmqgrmhxwsjax  demo-web-01kv2x6h  demo       1/1  running  less than a minutes
01kv2x6ppvmmmk915a4660brwd  demo-web-01kv2x6p  demo       1/1  running  less than a minutes

# service
$ raind resource service ls -n demo
SERVICE ID                  NAME      NAMESPACE  TYPE       PORTS       CREATED
01kv2x6ftbetxc6dp5r7cr337t  demo-svc  demo       ClusterIP  80->80/tcp  less than a minutes

# ingress
workshop@raind-dev-4ec1a7cf:~/manifest$ raind resource ingress ls -n demo
INGRESS ID                  NAME          NAMESPACE  HOSTS       TLS         PATHS                BACKENDS     CREATED
01kv2x6h2vmysh72jeff7mz2ph  demo-ingress  demo       demo.local  demo.local  demo.local/(Prefix)  demo-svc:80  less than a minutes

Ingressは一般的なkubernetesとは異なり、condenserに内蔵したgatewayで受ける構成です。
ServiceはClusterIPとしてPodへの安定した入口になり、IngressはHost/PathでServiceへルーティングします。
このあたりは、Kubernetesっぽい使い方をしつつも、実装は内蔵gateway/iptablesをベースとした軽量/シンプルな構成としてRaindの中で完結するようにしています。

Traffic Observability & Control

最後に、Raindでかなり重視しているのが通信の可視化と制御です。
RaindではコンテナやPodを起動するだけではなく、その通信をランタイムの中で扱えるようにしています。

ここはRaindの特徴的な機能のひとつなので、実際の操作をお見せします。

ポリシー追加

src-containerからwebのTCP/80への通信を許可します。

$ raind policy add --type ew -s src-container -d web -p tcp --dport 80
policy: 01kv2wh273j8ya1bq1yqgg2mnv created

ポイントは、IPではなくコンテナ名でポリシー設定を行える点です。

ポリシーコミット

ネットワーク制御は設定を誤ると影響が大きいため、明示的にcommitすることで実際のネットワーク制御へ反映します。

$ raind policy commit
This operation will affect the container network.
Are you sure you want to commit? (y/n): y
policy commit success

ポリシー確認

$ raind policy ls
FLAG: [*] - Applied, [+] - Apply next commit, [-] - Remove next commit, [ ] - Not applied

POLICY TYPE : East-West
CURRENT MODE: deny_by_default

FLAG  POLICY ID                   SRC CONTAINER  DST CONTAINER  PROTOCOL  DST PORT  ACTION  COMMENT  REASON
[*]   01kv2wax5mhdbka0f0j5jtcxxr  src-container  dst-container  icmp      *         ALLOW
[*]   01kv2wh273j8ya1bq1yqgg2mnv  src-container  web            tcp       80        ALLOW
  >> DENY ALL EAST-WEST TRAFFIC <<

============================
POLICY TYPE : North-South
CURRENT MODE: observe

FLAG  POLICY ID  SRC CONTAINER  DST ADDR  PROTOCOL  DST PORT  ACTION  COMMENT  REASON
  >> ALLOW ALL NORTH-SOUTH TRAFFIC <<

この出力で見えている通り、East-West(コンテナ間通信)はdeny_by_defaultです。
許可した通信だけが通ります。
一方で North-South(外部通信)はobserveです。
外部通信は許可しつつ、ログとして観測します。

通信ログ

実際の通信ログはこんな感じです。

$ raind logs netflow
2026-06-14 19:56:01     ALLOW   FROM: src-container => TO: dst-container {ICMP type=8 code=0}
2026-06-14 19:58:58     ALLOW   FROM: src-container => TO: dst-container {ICMP type=8 code=0}
2026-06-14 19:59:03     DENY    FROM: src-container => TO: web {ICMP type=8 code=0}
2026-06-14 19:59:03     DENY    FROM: src-container => TO: web {ICMP type=8 code=0}
2026-06-14 19:59:05     DENY    FROM: src-container => TO: web {ICMP type=8 code=0}
2026-06-14 19:59:13     ALLOW   FROM: src-container => TO: 151.101.2.132 {TCP/443}
2026-06-14 19:59:15     ALLOW   FROM: src-container => TO: 151.101.2.132 {TCP/443}
2026-06-14 19:59:20     ALLOW   FROM: src-container => TO: web {TCP/80}
2026-06-14 19:59:22     ALLOW   FROM: src-container => TO: web {TCP/80}

ポリシー設定と同じく、src-containerやwebのように、通信元・通信先がコンテナ名として確認が可能です。

Raindはランタイム内でコンテナやPodの状態を持っているので、通信ログを出すときにIPからコンテナ名へマッピングしています。
このあたりは、ランタイムとして通信を見ているからこそやりたかった部分です。

まとめ

Raindは、Docker的な単体コンテナ実行と、Kubernetes的なPod/Service/Ingressといったリソースを、1つのランタイムの中で扱うために作っています。

今できることをまとめると、こんな感じです。

Raind
  ├── Docker Like
  │   └── Single Container
  ├── Docker Compose Like
  │   └── Bottle
  ├── Kubernetes Like
  │   ├── Pod
  │   ├── Deployment
  │   ├── Service
  │   └── Ingress
  └── Runtime Level
      ├── Traffic Policy
      ├── Netflow Logs
      ├── DNS Observability
      └── Container/Pod name mapping

まだ実験的なランタイムですが、だいぶ形になってきました。
特に最近は、ClusterIP Service、HTTP/HTTPS Ingress、Ingress用TLS証明書、通信ポリシー、netflow可視化などがつながってきて、単なるコンテナ起動ツールではなく「workload runtime」として見えてきた感じがあります。

今後は、Ingress の拡張、TLS 周りの整理、policy / observability の強化、runtime の安定化あたりを進めていく予定です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?