目次
1. はじめに
2. 環境
3. インストール手順
4. 発生したエラー
5. まとめ
参考 URL
- ETSI NFV-SOL CNF (Containerized VNF) Deployment
- VNF と CNF の違い
- VNF Package
- Kubernetes VIM Installation
- Master NodeにPodをデプロイするための設定
- Kuryr installation as a Kubernetes network addon
はじめに
こんにちは。新入社員として約 3 か月目の新人です。
この記事では NFV という言葉すら知らなかった新人が Install via Devstack を参考にして DevStack 環境をインストールし、VIM として OpenStack と Kubernetes を登録するまでの手順と発生したエラーを複数の章に分けて記載していきます。
Install via Devstack を実際に試します。
ETSI NFV-SOL VNF Deployment as VM with TOSCA を実際に試します。
ETSI NFV-SOL VNF Deployment as VM with LCM Operation User Data を実際に試します。
- 第 4 章: この記事です。
ETSI NFV-SOL CNF (Containerized VNF) Deployment を実際に試します。
今回のインストールで自分が調べた用語は以下にまとめました。
CNF (Containerized Network Function)
コンテナ化されたネットワーク機能を提供します。
CSAR (Cloud Service Archive)
ZIP ファイル形式を使用したアーカイブファイルです。
その構造は TOSCA Simple Profile YAML v1.2 仕様に準拠しています。
アーカイブするファイル構造は VNF Package に記載されています。
環境
ESXi 上に Devstack をインストールし、環境に対して一部設定を追加しています。
詳しくは 新人が DevStack 上で Tacker を動かそうとする話 と 新人が DevStack 上で TOSCA を使用して VNF を VM としてデプロイする話 をお読みください。
インストール手順
この手順は本環境でインストール完了までうまくいったものです。
手順完成までに発生したエラーは 4. 発生したエラー にまとめます。
実行ユーザとディレクトリ
stack ユーザで実行します。
sudo -u stack -i
自分で作成したファイルを配置する work ディレクトリを作成します。
mkdir ~/work/
work ディレクトリに移動します。
cd ~/work
Kubernetes 環境の準備 (kubeadm)
Tacker が ETSINFV-SOL コンテナ化 VNF を Kubernetes にデプロイする方法について記載します。
本環境では kuryr-kubernetes が動作しないため、Devstack 内の Kubernetes を VIM として利用できませんでした。
この kuryr-kubernetes は VM を再起動すると停止し、動作しなくなります。
原因は現在も不明です。
そのため、新しい VM 上に kubeadm で Kubernetes を起動させ、VIM として利用します。
この手順は Devstack を動作させている環境とは別の環境で動作させなければなりません。
Devstack を動作させている環境では etcd が動作しています。
そのため、同環境へ新たに Kubernetes を動作させると etcd が競合してしまいます。
本手順完了後の環境は下記の図のようになります。
この図は 1. はじめに で述べた章をすべて実施済みの状態です。
swap の無効化
Kubernetes の init 時にエラーが発生してしまうため、swap を無効化します。
fstab のバックアップファイルを作成します。
sudo cp -ai /etc/fstab{,.default}
swap を無効化します。
下記の項目をコメントアウトします。
$ vim /etc/fstab
/swap.img none swap sw 0 0
確認します。
$ diff /etc/fstab{.default,}
12c12
< /swap.img none swap sw 0 0
---
> #/swap.img none swap sw 0 0
この設定により再起動後も swap が無効化された状態で起動しますが、再起動なしで swap を無効化する場合は下記を実行します。
sudo swapoff -a
カーネルパラメータの設定
ネットワークブリッジを通過するパケットに対し iptables ルールを適用するかどうかを指定するカーネルパラメータ net.bridge.bridge-nf-call-iptables を確認します。
1 と設定されている場合は問題ありません。
$ cat /proc/sys/net/bridge/bridge-nf-call-iptables
1
0 と設定されている場合は以下を実行することで設定を 1 に変更します。
echo net.bridge.bridge-nf-call-iptables = 1 > /etc/sysctl.d/99-bridge-nf-call-iptables
sysctl -p /etc/sysctl.d/99-bridge-nf-call-iptables
Docker driver の変更
Kubernetes v1.21 から、kubeadm の標準の cgroup の driver が cgroupfs から systemd に変更されました。
そのため、docker の driver を確認し、必要であれば systemd に変更します。
確認します。
$ docker info | grep Cgroup
Cgroup Driver: cgroupfs
Cgroup Version: 1
daemon.json のバックアップを作成します。
sudo cp -ai /etc/docker/daemon.json{,.default}
daemon.json ファイルに下記を追記します。
$ sudo vim /etc/docker/daemon.json
・・・
"exec-opts": ["native.cgroupdriver=systemd"],
・・・
daemon のリロードと docker.service の再起動を行います。
sudo systemctl daemon-reload
sudo systemctl restart docker.service
設定を確認します。
$ docker info | grep Cgroup
Cgroup Driver: systemd
Cgroup Version: 1
Master ノードのセットアップ
Kubernetes クラスタの構築をします。
$ sudo kubeadm init --pod-network-cidr=10.244.0.0/16
I0715 06:29:47.841987 107552 version.go:255] remote version is much newer: v1.24.3; falling back to: stable-1.22
[init] Using Kubernetes version: v1.22.12
[preflight] Running pre-flight checks
[preflight] Pulling images required for setting up a Kubernetes cluster
[preflight] This might take a minute or two, depending on the speed of your internet connection
[preflight] You can also perform this action in beforehand using 'kubeadm config images pull'
[certs] Using certificateDir folder "/etc/kubernetes/pki"
[certs] Generating "ca" certificate and key
[certs] Generating "apiserver" certificate and key
[certs] apiserver serving cert is signed for DNS names [kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local yoshitest] and IPs [10.96.0.1 10.100.2.210]
[certs] Generating "apiserver-kubelet-client" certificate and key
[certs] Generating "front-proxy-ca" certificate and key
[certs] Generating "front-proxy-client" certificate and key
[certs] Generating "etcd/ca" certificate and key
[certs] Generating "etcd/server" certificate and key
[certs] etcd/server serving cert is signed for DNS names [localhost yoshitest] and IPs [10.100.2.210 127.0.0.1 ::1]
[certs] Generating "etcd/peer" certificate and key
[certs] etcd/peer serving cert is signed for DNS names [localhost yoshitest] and IPs [10.100.2.210 127.0.0.1 ::1]
[certs] Generating "etcd/healthcheck-client" certificate and key
[certs] Generating "apiserver-etcd-client" certificate and key
[certs] Generating "sa" key and public key
[kubeconfig] Using kubeconfig folder "/etc/kubernetes"
[kubeconfig] Writing "admin.conf" kubeconfig file
[kubeconfig] Writing "kubelet.conf" kubeconfig file
[kubeconfig] Writing "controller-manager.conf" kubeconfig file
[kubeconfig] Writing "scheduler.conf" kubeconfig file
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Starting the kubelet
[control-plane] Using manifest folder "/etc/kubernetes/manifests"
[control-plane] Creating static Pod manifest for "kube-apiserver"
[control-plane] Creating static Pod manifest for "kube-controller-manager"
[control-plane] Creating static Pod manifest for "kube-scheduler"
[etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests"
[wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests". This can take up to 4m0s
[apiclient] All control plane components are healthy after 17.502563 seconds
[upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace
[kubelet] Creating a ConfigMap "kubelet-config-1.22" in namespace kube-system with the configuration for the kubelets in the cluster
[upload-certs] Skipping phase. Please see --upload-certs
[mark-control-plane] Marking the node yoshitest as control-plane by adding the labels: [node-role.kubernetes.io/master(deprecated) node-role.kubernetes.io/control-plane node.kubernetes.io/exclude-from-external-load-balancers]
[mark-control-plane] Marking the node yoshitest as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule]
[bootstrap-token] Using token: slx8x6.kvl1eks1u9auzbm6
[bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles
[bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to get nodes
[bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials
[bootstrap-token] configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token
[bootstrap-token] configured RBAC rules to allow certificate rotation for all node client certificates in the cluster
[bootstrap-token] Creating the "cluster-info" ConfigMap in the "kube-public" namespace
[kubelet-finalize] Updating "/etc/kubernetes/kubelet.conf" to point to a rotatable kubelet client certificate and key
[addons] Applied essential addon: CoreDNS
[addons] Applied essential addon: kube-proxy
Your Kubernetes control-plane has initialized successfully!
To start using your cluster, you need to run the following as a regular user:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Alternatively, if you are the root user, you can run:
export KUBECONFIG=/etc/kubernetes/admin.conf
You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join 10.100.2.210:6443 --token slx8x6.kvl1eks1u9auzbm6 \
--discovery-token-ca-cert-hash sha256:06c48716c874f3565250f79837e07db67e7e98e493d45072818a335c07f0a633
.kube ディレクトリをホームディレクトリに配置します。
これにより kubectl コマンドなどが使用可能になります。
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Kubernetes が動作状況を確認します。
$ kubectl get node
NAME STATUS ROLES AGE VERSION
yoshitest Ready control-plane,master 11m v1.22.3
$ kubectl get pod --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-78fcd69978-bflnm 0/1 ContainerCreating 0 11m
kube-system coredns-78fcd69978-dh6kg 0/1 ContainerCreating 0 11m
kube-system etcd-yoshitest 1/1 Running 1 11m
kube-system kube-apiserver-yoshitest 1/1 Running 1 11m
kube-system kube-controller-manager-yoshitest 1/1 Running 1 11m
kube-system kube-proxy-p84m8 1/1 Running 0 11m
kube-system kube-scheduler-yoshitest 1/1 Running 1 11m
CNI インストール
CNI プラグインとして Calico をインストールします。
作業用のディレクトリは ~/work/calico とします。
mkdir -p ~/work/calico
cd ~/work/calico
インストールに必要なファイルをダウンロードします。
curl https://projectcalico.docs.tigera.io/manifests/tigera-operator.yaml -O
curl https://projectcalico.docs.tigera.io/manifests/custom-resources.yaml -O
customer-resources.yaml の spec.calicoNetwork.ipPools.cidr の値を kubeadm init --pod-network-cidr=
で指定した値に変更します。
$ vim custom-resources.yaml
・・・
spec:
# Configures Calico networking.
calicoNetwork:
# Note: The ipPools section cannot be modified post-install.
ipPools:
- blockSize: 26
cidr: 10.244.0.0/16
・・・
Calico をインストールします。
kubectl apply -f tigera-operator.yaml
kubectl apply -f custom-resources.yaml
起動確認します。
$ kubectl get pod -n tigera-operator
NAME READY STATUS RESTARTS AGE
tigera-operator-d8cbfddcc-dmfww 1/1 Running 0 29s
$ kubectl get pod -n calico-system
NAME READY STATUS RESTARTS AGE
calico-kube-controllers-7f87b64bd9-fzshn 1/1 Running 0 5m13s
calico-node-dgwhm 1/1 Running 0 5m13s
calico-typha-5fdf9ffc5c-bvmp9 1/1 Running 0 5m14s
Master ノードの Taint 情報削除
今回は Worker ノードを作成せず、Master ノードのみで動作させます。
Master ノードには Pod が展開されないようにするためにデフォルトで node-role.kubernetes.io/master:NoSchedule という Taint が付与されています。
このままでは Worker ノードを準備しない限り Pod が展開できないため、本環境ではこの Taint 情報を削除します。
$ kubectl get node
NAME STATUS ROLES AGE VERSION
yoshitest Ready control-plane,master 33m v1.22.3
$ kubectl taint nodes yoshitest node-role.kubernetes.io/master:NoSchedule-
node/yoshitest untainted
サンプルマニフェストの起動確認
サンプルのマニフェストとして下記のマニフェストファイルを準備し、Pod の起動を試します。
$ cat << _EOF_ > sample.yaml
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2 # tells deployment to run 2 pods matching the template
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
_EOF_
起動します。
kubectl apply -f sample.yaml
確認します。
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-deployment-66b6c48dd5-glcrt 1/1 Running 0 10m
nginx-deployment-66b6c48dd5-t7s4n 1/1 Running 0 10m
Kubernetes VIM
ここから先の作業は基本的に Devstack が動作しているマシン上で実施してください。
[VIM 用の設定ファイル作成に必要な情報取得] のみ Kubernetes Master ノードで実施します。
VIM 用の設定ファイル作成に必要な情報取得
ファイル作成に必要な下記の値を収集します。
この手順のみ Kubernetes Master ノードで実施します。
- auth_url
<自身の IP>:6443 です。
コマンドで調べる場合は下記の通りです。
$ kubectl cluster-info
Kubernetes control plane is running at https://10.100.2.210:6443
CoreDNS is running at https://10.100.2.210:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
- bearer_token
ベアトークンを含む Kubernetes シークレット名を確認します。
Kubernetes データモデルでは、.data に含まれる値は Base64 形式でエンコードされるため、ベアトークンとして使用するには、base64 --decode
または base64 -d
コマンドでデコードする必要があります。
$ kubectl get secret
NAME TYPE DATA AGE
default-token-qm98x kubernetes.io/service-account-token 3 59m
$ TOKEN=$(kubectl get secret default-token-qm98x -o jsonpath="{.data.token}" | base64 --decode) && echo $TOKEN
eyJhbGciOiJSUzI1NiIsImtpZCI6IjNGVXpEeGIxbU9xMGY0NEpEeGt4bkhrMDJidU9GSUVMUFN0RlRGMi16R1kifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImRlZmF1bHQtdG9rZW4tcW05OHgiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGVmYXVsdCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6ImY2MGQxYWNlLTU3YmQtNDY1OC05YTBjLWIxMTdmMzNmY2EyYiIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmRlZmF1bHQifQ.kPwKalaP5123zJ7Lw29PCHpT_mU5uwjUkbtKFbn9rtCfUAXCEwOveTFf3F9s08RudaQKy5CJQrj5TqAS_7lQ2EQePKBL6_pW9YKxqUUNRw8krF7xa-ghTON2B0HKdTl51ZMPKwgjLkydrvH7JQT5C11WBbot0auct-m2wBlL1M8ahUdaHcv--nCHm4JF7NKMd8wW0ASmGBGV3Fei8GEUVMCp-GicrDzp8A0dgbVY9NZkWoed4cP6eSsVN_FaHwt2V4SqrvgjkNvDttFID9sL7UkcKGz8KIJSLzQnX6DVDuUyXjSpz7TsvAN2-DV2oO8fn35WlhLw9YZQ3t264qs0bQ
このトークンを使用する前に、ユーザーはこのトークンに管理者の役割を適用する必要があります。
$ kubectl create clusterrolebinding cluster-admin-binding \
--clusterrole cluster-admin --serviceaccount=default:default
clusterrolebinding.rbac.authorization.k8s.io/cluster-admin-binding created
- ssl_ca_cert
Kubernetes クラスターへの認証に関する詳細情報を入手します。
$ kubectl get secrets default-token-qm98x -o jsonpath="{.data.ca\.crt}" | base64 --decode
-----BEGIN CERTIFICATE-----
MIIC/jCCAeagAwIBAgIBADANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDEwprdWJl
cm5ldGVzMB4XDTIyMDcxNTA2Mjk0OVoXDTMyMDcxMjA2Mjk0OVowFTETMBEGA1UE
AxMKa3ViZXJuZXRlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK6q
Q/LNRChV6tw2ucfNhV8sBBvWyt+0KtFyDA16h7Tm49wBBzx/Y/cF4UGBFUETcYgA
9zUbrcPqnBeyVXD9Td5R0y/oqPXuX3wBzetalcSe3OlZiAiG28asWf1jaXGCDgmk
hfQBz2OQi0jO98XoG014ok7Ortgz0v6ZV/9tcGPCwxlsERRXCYpeytHE4aCI/aky
8fnT7SGQ506WD7x4DnSYluH5ceH3NeQ56qIsLZUk4G75LVSTr26r7bds6n81urgV
pJi9OMaxA1SWveEoH5serSy5nNfLzjFZhS7r3KDkUl3yokltlQq61K3rHLNQoz+Z
+BpklMSQj8a9thkylj8CAwEAAaNZMFcwDgYDVR0PAQH/BAQDAgKkMA8GA1UdEwEB
/wQFMAMBAf8wHQYDVR0OBBYEFFNNpaDF4hs8BcdxmNoUyUcvVomAMBUGA1UdEQQO
MAyCCmt1YmVybmV0ZXMwDQYJKoZIhvcNAQELBQADggEBAF72CNi5EUFeUYLxP9Qf
buSD2hQaDcgBr+W9de/BFGXF1jm+lUag92Jd7+EIHwt27Pf4mRpZLce6pB3bhzQ6
oc7b5vs9k3B+3gByPKW52RZrz7cXL1nfz2TxgBEqiruZiviZiZB7f/KkMZDeU+fW
c5R96oBr4/eGqtTh2P6q5UKYixOoYjhnZGCQOYG+SJInIqKQUBmbqaazCXCZNxdv
1fPzBe73AnMdiFl9AzEc38htf912dh5SRzKmkH47cU/m+7GbzXLsjhOtGWay/rV4
thpePCADCWBYrL62VZoRJs+VW7jNPTJwTMkfUuKN6KwSXugJVvAGRVsrV9rnTuOO
sbQ=
-----END CERTIFICATE-----
API エンドポイントとベアラートークンが使用可能であることを確認できます。
$ curl -k https://10.100.2.210:6443/api/ -H "Authorization: Bearer $TOKEN"
{
"kind": "APIVersions",
"versions": [
"v1"
],
"serverAddressByClientCIDRs": [
{
"clientCIDR": "0.0.0.0/0",
"serverAddress": "10.100.2.210:6443"
},
{
"clientCIDR": "10.96.0.0/12",
"serverAddress": "10.96.0.1:443"
}
]
}
VIM 用の設定ファイル作成
取得した情報を利用して構成ファイルを作成します。
ここから先の手順は Devstack が動作しているマシン上で実施します。
cat << _EOF_ > ~/work/vim-k8s.yaml
auth_url: "https://10.100.2.210:6443"
project_name: "default"
bearer_token: "eyJhbGciOiJSUzI1NiIsImtpZCI6IjNGVXpEeGIxbU9xMGY0NEpEeGt4bkhrMDJidU9GSUVMUFN0RlRGMi16R1kifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImRlZmF1bHQtdG9rZW4tcW05OHgiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGVmYXVsdCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6ImY2MGQxYWNlLTU3YmQtNDY1OC05YTBjLWIxMTdmMzNmY2EyYiIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmRlZmF1bHQifQ.kPwKalaP5123zJ7Lw29PCHpT_mU5uwjUkbtKFbn9rtCfUAXCEwOveTFf3F9s08RudaQKy5CJQrj5TqAS_7lQ2EQePKBL6_pW9YKxqUUNRw8krF7xa-ghTON2B0HKdTl51ZMPKwgjLkydrvH7JQT5C11WBbot0auct-m2wBlL1M8ahUdaHcv--nCHm4JF7NKMd8wW0ASmGBGV3Fei8GEUVMCp-GicrDzp8A0dgbVY9NZkWoed4cP6eSsVN_FaHwt2V4SqrvgjkNvDttFID9sL7UkcKGz8KIJSLzQnX6DVDuUyXjSpz7TsvAN2-DV2oO8fn35WlhLw9YZQ3t264qs0bQ"
ssl_ca_cert: "-----BEGIN CERTIFICATE-----
MIIC/jCCAeagAwIBAgIBADANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDEwprdWJl
cm5ldGVzMB4XDTIyMDcxNTA2Mjk0OVoXDTMyMDcxMjA2Mjk0OVowFTETMBEGA1UE
AxMKa3ViZXJuZXRlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK6q
Q/LNRChV6tw2ucfNhV8sBBvWyt+0KtFyDA16h7Tm49wBBzx/Y/cF4UGBFUETcYgA
9zUbrcPqnBeyVXD9Td5R0y/oqPXuX3wBzetalcSe3OlZiAiG28asWf1jaXGCDgmk
hfQBz2OQi0jO98XoG014ok7Ortgz0v6ZV/9tcGPCwxlsERRXCYpeytHE4aCI/aky
8fnT7SGQ506WD7x4DnSYluH5ceH3NeQ56qIsLZUk4G75LVSTr26r7bds6n81urgV
pJi9OMaxA1SWveEoH5serSy5nNfLzjFZhS7r3KDkUl3yokltlQq61K3rHLNQoz+Z
+BpklMSQj8a9thkylj8CAwEAAaNZMFcwDgYDVR0PAQH/BAQDAgKkMA8GA1UdEwEB
/wQFMAMBAf8wHQYDVR0OBBYEFFNNpaDF4hs8BcdxmNoUyUcvVomAMBUGA1UdEQQO
MAyCCmt1YmVybmV0ZXMwDQYJKoZIhvcNAQELBQADggEBAF72CNi5EUFeUYLxP9Qf
buSD2hQaDcgBr+W9de/BFGXF1jm+lUag92Jd7+EIHwt27Pf4mRpZLce6pB3bhzQ6
oc7b5vs9k3B+3gByPKW52RZrz7cXL1nfz2TxgBEqiruZiviZiZB7f/KkMZDeU+fW
c5R96oBr4/eGqtTh2P6q5UKYixOoYjhnZGCQOYG+SJInIqKQUBmbqaazCXCZNxdv
1fPzBe73AnMdiFl9AzEc38htf912dh5SRzKmkH47cU/m+7GbzXLsjhOtGWay/rV4
thpePCADCWBYrL62VZoRJs+VW7jNPTJwTMkfUuKN6KwSXugJVvAGRVsrV9rnTuOO
sbQ=
-----END CERTIFICATE-----"
type: "kubernetes"
_EOF_
Kubernetes VIM の登録
Kubernetes VIM を Tacker に登録します。
test-vim-k8s-kubeadm は登録する Kubernetes VIM の名前です。
$ openstack vim register --config-file vim-k8s.yaml test-vim-k8s-kubeadm --fit-width
+----------------+---------------------------------------------------------------------------------------------------------+
| Field | Value |
+----------------+---------------------------------------------------------------------------------------------------------+
| auth_cred | { |
| | "bearer_token": "***", |
| | "ssl_ca_cert": "b'gAAAAABi0SJYjdfgr98GZaz2sFM5kRw8ZDgZUWkWFwdqQaE1uRLcOiQz3qW4Si66ECS7vApgPHieINreB |
| | k4ECVvZH9CUGyQWCW1FvVsM7U_6M2jpVjsPDTE9s2h78WI4OIA_qw24zQtafubWuWmMeAv2h3ZtIeeo8vxrxMt6UsVNlpgyFrDE6fyG |
| | 0zZ7j9-HFFbHxTUXrr75maiBqQISmzpxvcG-URCyb- |
| | qdJIqPKSZ38isVlzpU5NpgEuuTxqMBdNPADGzUk0eGDiBHNLRjNQ1j-braFxFR9iXfxpHcsLbKtZztaacO- |
| | uJEjtpL1yXZ1lPbwGXurwWf4j2UzsxrnsWoHR1rdNV5PCnefIj- |
| | PIEub_kVOWSF33YuFqHgR7XbkAmMGJalRzE521rCGA64BlG7k1Es- |
| | SyN89YCeEEtnIVf6Kk3ylXfnw0SIefuN48VSj0UV1WJlkcEzXPTAEWueUIjj9pAxaaCW- |
| | znFpqv4_3NZDyG5RYEuDqNo8pi7Vj4kBsT9NK-RcCeAg3cCQcaKsi_SD0NQ0NoWQd5eKWelSeDxTzhTlYpIN_SD7f85ab- |
| | pKPrp4x_F-rPgTcOchrtYBQ3yZvg-zNihmuQLe1yKa_Hf9RjKzc5_I_t4pjoPy140n3QyefuM8yGN973MovEXe8WrjcS_z02VHs_nYB |
| | 1snD4vxhnbUVxNy0TbnAvcujVR_Y2jzw71iUsNVVwXLT3-81xcs5T7B6m-aFH0icyLQy3Ixvj-mm4GVbya8xCGidIaF1iIBV-NXHUng |
| | 0jmsGxRnoOfmLnUef1ek_TFYLmv43cbhbLLdiaPMMWdYdhN5z7AoJiWhL6cVlKmsd1WWKjBPW_GqQgFnlqN1l6CeL5G5_GFfsulcLxk |
| | b06Astvyvv0yMozjHgBMI79WbYmOyqo0NnMCkJFnJLAumP-jy_RtHeKpV8tq41j7BSm-ehc2vdgiWSuCXI5m0J49sDv9yQ631UBQmTf |
| | Nve1ANonQBIB6_sMon52chThE0JL6QtX_N4y0pe0HCyibQAh5a6d0qo2yUAQXS9pPctPkXw7IQpCi2pfr6WmD4SxY5GVegjZg6ySlY6 |
| | X-yShYHw88_ixnulGnLZDcXZp9Y14XwYCGOdY25wekuuvronkKJVnb7cedDV6jj8jTYwkLBuQLfAeJI7nG78DsrOs- |
| | PlsVv4M2hgCgEbDRKckw9ZHcnPAKSGYGP-ongmwhobbkRYLCi8qSuSuCsUT47AvGjsC7yOUDVk0iX-DrQ2V5R-Nns- |
| | pWOj25kz5EB0FxNkAWjVjyMaXYw3Ic3_p_hciOj6eE1CtIsVncHF50TlXVkOMrsbzgpH7zWRrbHh4VFKuk66Zrtgh- |
| | iGv8LkhpOqLoG7x6ayfVmxjzZU2i--F4AKc8EBPXj-_05n6EeOgIEe4szLpUUy_UfeHsYhgkEeGkWWA6RR0HpzF- |
| | uwKnsX1aMfCdFTUmnuvrJWnRJhAsMG-G3sChGo90_G5nNhbXMf6YWcMk8pocNjvVNLJ6vqvgH5aEsnSklbmI2XYHbFRgbCeKRJp'", |
| | "auth_url": "https://10.100.2.210:6443", |
| | "username": "None", |
| | "key_type": "barbican_key", |
| | "secret_uuid": "***", |
| | "password": "***" |
| | } |
| auth_url | https://10.100.2.210:6443 |
| created_at | 2022-07-15 08:16:25.496115 |
| description | |
| id | e31459a6-1380-4fd8-930b-a70dc0500614 |
| is_default | False |
| name | test-vim-k8s-kubeadm |
| placement_attr | { |
| | "regions": [ |
| | "calico-apiserver", |
| | "calico-system", |
| | "default", |
| | "kube-node-lease", |
| | "kube-public", |
| | "kube-system", |
| | "tigera-operator" |
| | ] |
| | } |
| project_id | cd492cafc33c4d6b878ee570f6aeae21 |
| status | PENDING |
| type | kubernetes |
| updated_at | None |
| vim_project | { |
| | "name": "default" |
| | } |
+----------------+---------------------------------------------------------------------------------------------------------+
登録した VIM の Status が REACHABLE であるかどうかを確認します。
$ openstack vim list
+--------------------------------------+----------------------+----------------------------------+------------+------------+-----------+
| ID | Name | Tenant_id | Type | Is Default | Status |
+--------------------------------------+----------------------+----------------------------------+------------+------------+-----------+
| e31459a6-1380-4fd8-930b-a70dc0500614 | test-vim-k8s-kubeadm | cd492cafc33c4d6b878ee570f6aeae21 | kubernetes | False | REACHABLE |
+--------------------------------------+----------------------+----------------------------------+------------+------------+-----------+
環境変数として VIM ID を定義しておきます。
export VIM_ID=e31459a6-1380-4fd8-930b-a70dc0500614
VNF パッケージの準備
VNF パッケージには、VNFD に加えて CNF 定義が含まれている必要があります。
VNF パッケージのディレクトリの作成
VNF パッケージを配置するディレクトリを作成します。
mkdir -p ~/work/deployment/{TOSCA-Metadata,Definitions,Files/kubernetes}
Kubernetes オブジェクトファイルの作成
CSAR VNF パッケージには、デプロイする Kubernetes リソースを定義するオブジェクトファイルが含まれている必要があります。
様々な yaml ファイルのコンテンツに応じて、KubernetesAPI リソースを作成できます。
簡単な Deployment リソースを作成します。
cat << _EOF_ > ~/work/deployment/Files/kubernetes/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: curry-probe-test001
namespace: default
spec:
replicas: 1
selector:
matchLabels:
selector: curry-probe-test001
template:
metadata:
labels:
selector: curry-probe-test001
app: webserver
spec:
containers:
- name: nginx-liveness-probe
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
protocol: TCP
- image: celebdor/kuryr-demo
imagePullPolicy: IfNotPresent
name: kuryr-demo-readiness-probe
ports:
- containerPort: 8080
protocol: TCP
_EOF_
インスタンス化パラメーターに vdu_mapping が含まれていない場合、このファイルの metadata.name は、デプロイメントフレーバー定義ファイルの対応する VDU の properties.name と同じである必要があります。
今回の手順では metadata.name は後程作成する helloworld3_df_simple.yaml ファイルの topology_template.node_templates.VDU1.properties.name と同じです。
TOSCA.meta ファイルの作成
TOSCA.Meta ファイルには、TOSCA.Meta ファイル、CSAR のバージョンや定義ファイルファイルの情報が含まれています。
また、Artifact ファイルの名前、コンテンツタイプ、暗号化方式、および Artifact ファイルのハッシュ値が必要です。
ここでの Artifact ファイルとは作成したオブジェクトファイルが該当します。
Artifact ファイルのハッシュ値を取得します。
$ sha256sum ~/work/deployment/Files/kubernetes/deployment.yaml
4154adca79b0dc3829f69c82758736df674ffdd89603b4e827bd81afab6b4028 deployment/Files/kubernetes/deployment.yaml
TOSCA.meta ファイルを作成します。
cat << _EOF_ > ./deployment/TOSCA-Metadata/TOSCA.meta
TOSCA-Meta-File-Version: 1.0
Created-by: dummy_user
CSAR-Version: 1.1
Entry-Definitions: Definitions/helloworld3_top.vnfd.yaml
Name: Files/kubernetes/deployment.yaml
Content-Type: application/yaml
Algorithm: SHA-256
Hash: 4154adca79b0dc3829f69c82758736df674ffdd89603b4e827bd81afab6b4028
_EOF_
ETSI 定義ファイルのダウンロード
公式文書をダウンロードします。
ETSI GS NFV-SOL 001 は、TOSCA 仕様に基づいて VNFD の構造と形式を指定します。
cd ~/work/deployment/Definitions
wget https://forge.etsi.org/rep/nfv/SOL001/raw/v2.6.1/etsi_nfv_sol001_common_types.yaml
wget https://forge.etsi.org/rep/nfv/SOL001/raw/v2.6.1/etsi_nfv_sol001_vnfd_types.yaml
VNFD の作成
CNF に必要なすべてのコンポーネントが Kubernetes リソースファイルで指定されるため、VNFD には VDU、接続ポイント、仮想リンクなどの Kubernetes リソース情報は含まれません。
CNF の定義を含む VNFD ファイルを作成します。
cat << _EOF_ > ~/work/deployment/Definitions/helloworld3_top.vnfd.yaml
tosca_definitions_version: tosca_simple_yaml_1_2
description: Sample VNF
imports:
- etsi_nfv_sol001_common_types.yaml
- etsi_nfv_sol001_vnfd_types.yaml
- helloworld3_types.yaml
- helloworld3_df_simple.yaml
topology_template:
inputs:
selected_flavour:
type: string
description: VNF deployment flavour selected by the consumer. It is provided in the API
node_templates:
VNF:
type: company.provider.VNF
properties:
flavour_id: { get_input: selected_flavour }
descriptor_id: b1bb0ce7-ebca-4fa7-95ed-4840d7000003
provider: Company
product_name: Sample VNF
software_version: '1.0'
descriptor_version: '1.0'
vnfm_info:
- Tacker
requirements:
#- virtual_link_external # mapped in lower-level templates
#- virtual_link_internal # mapped in lower-level templates
_EOF_
VNF のパラメータータイプとデフォルト値を定義します。
cat << _EOF_ > ~/work/deployment/Definitions/helloworld3_types.yaml
tosca_definitions_version: tosca_simple_yaml_1_2
description: VNF type definition
imports:
- etsi_nfv_sol001_common_types.yaml
- etsi_nfv_sol001_vnfd_types.yaml
node_types:
company.provider.VNF:
derived_from: tosca.nodes.nfv.VNF
properties:
descriptor_id:
type: string
constraints: [ valid_values: [ b1bb0ce7-ebca-4fa7-95ed-4840d7000003 ] ]
default: b1bb0ce7-ebca-4fa7-95ed-4840d7000003
descriptor_version:
type: string
constraints: [ valid_values: [ '1.0' ] ]
default: '1.0'
provider:
type: string
constraints: [ valid_values: [ 'Company' ] ]
default: 'Company'
product_name:
type: string
constraints: [ valid_values: [ 'Sample VNF' ] ]
default: 'Sample VNF'
software_version:
type: string
constraints: [ valid_values: [ '1.0' ] ]
default: '1.0'
vnfm_info:
type: list
entry_schema:
type: string
constraints: [ valid_values: [ Tacker ] ]
default: [ Tacker ]
flavour_id:
type: string
constraints: [ valid_values: [ simple ] ]
default: simple
flavour_description:
type: string
default: "falvour"
requirements:
- virtual_link_external:
capability: tosca.capabilities.nfv.VirtualLinkable
- virtual_link_internal:
capability: tosca.capabilities.nfv.VirtualLinkable
_EOF_
VNF 入力のパラメータータイプを定義します。
cat << _EOF_ > ~/work/deployment/Definitions/helloworld3_df_simple.yaml
tosca_definitions_version: tosca_simple_yaml_1_2
description: Simple deployment flavour for Sample VNF
imports:
- etsi_nfv_sol001_common_types.yaml
- etsi_nfv_sol001_vnfd_types.yaml
- helloworld3_types.yaml
topology_template:
inputs:
descriptor_id:
type: string
descriptor_version:
type: string
provider:
type: string
product_name:
type: string
software_version:
type: string
vnfm_info:
type: list
entry_schema:
type: string
flavour_id:
type: string
flavour_description:
type: string
substitution_mappings:
node_type: company.provider.VNF
properties:
flavour_id: simple
requirements:
virtual_link_external: []
node_templates:
VNF:
type: company.provider.VNF
properties:
flavour_description: A simple flavour
VDU1:
type: tosca.nodes.nfv.Vdu.Compute
properties:
name: curry-probe-test001
description: kubernetes controller resource as VDU
vdu_profile:
min_number_of_instances: 1
max_number_of_instances: 3
policies:
- scaling_aspects:
type: tosca.policies.nfv.ScalingAspects
properties:
aspects:
vdu1_aspect:
name: vdu1_aspect
description: vdu1 scaling aspect
max_scale_level: 2
step_deltas:
- delta_1
- vdu1_initial_delta:
type: tosca.policies.nfv.VduInitialDelta
properties:
initial_delta:
number_of_instances: 1
targets: [ VDU1 ]
- vdu1_scaling_aspect_deltas:
type: tosca.policies.nfv.VduScalingAspectDeltas
properties:
aspect: vdu1_aspect
deltas:
delta_1:
number_of_instances: 1
targets: [ VDU1 ]
- instantiation_levels:
type: tosca.policies.nfv.InstantiationLevels
properties:
levels:
instantiation_level_1:
description: Smallest size
scale_info:
vdu1_aspect:
scale_level: 0
instantiation_level_2:
description: Largest size
scale_info:
vdu1_aspect:
scale_level: 2
default_level: instantiation_level_1
- vdu1_instantiation_levels:
type: tosca.policies.nfv.VduInstantiationLevels
properties:
levels:
instantiation_level_1:
number_of_instances: 1
instantiation_level_2:
number_of_instances: 3
targets: [ VDU1 ]
_EOF_
VNF パッケージの圧縮
CSAR パッケージはアップロード用に zip ファイルに圧縮する必要があります。
cd ~/work/deployment
zip deployment.zip -r Definitions/ Files/ TOSCA-Metadata/
VNF パッケージの作成とアップロード
Tacker で空の VNF パッケージオブジェクトを作成し、作成した圧縮 VNF パッケージをアップロードします。
VNF パッケージの作成
空の VNF パッケージを作成します。
VNF パッケージが正常に作成されると、ID、リンク、オンボーディング状態、運用状態、使用状態などの情報が返されます。
$ openstack vnf package create
+-------------------+-------------------------------------------------------------------------------------------------+
| Field | Value |
+-------------------+-------------------------------------------------------------------------------------------------+
| ID | d765618d-a455-4fc5-99e2-ab457d34f92c |
| Links | { |
| | "self": { |
| | "href": "/vnfpkgm/v1/vnf_packages/d765618d-a455-4fc5-99e2-ab457d34f92c" |
| | }, |
| | "packageContent": { |
| | "href": "/vnfpkgm/v1/vnf_packages/d765618d-a455-4fc5-99e2-ab457d34f92c/package_content" |
| | } |
| | } |
| Onboarding State | CREATED |
| Operational State | DISABLED |
| Usage State | NOT_IN_USE |
| User Defined Data | {} |
+-------------------+-------------------------------------------------------------------------------------------------+
VNF パッケージ ID を環境変数として登録します。
export VNF_PACKAGE_ID=d765618d-a455-4fc5-99e2-ab457d34f92c
確認します。
下記の状態であれば、作成が成功したことを示します。
$ openstack vnf package show $VNF_PACKAGE_ID \
-c 'Onboarding State' -c 'Operational State' -c 'Usage State'
+-------------------+------------+
| Field | Value |
+-------------------+------------+
| Onboarding State | CREATED |
| Operational State | DISABLED |
| Usage State | NOT_IN_USE |
+-------------------+------------+
VNF パッケージをアップロード
[VNF パッケージの圧縮] で作成した zip ファイルを作成した空の VNF パッケージにアップロードします。
cd ~/work/deployment
$ openstack vnf package upload --path deployment.zip $VNF_PACKAGE_ID
Upload request for VNF package 082f732d-4cb3-474b-8be0-cdace3224c6f has been accepted.
確認します。
下記の状態であれば問題ありません。
$ openstack vnf package show $VNF_PACKAGE_ID \
-c 'Onboarding State' -c 'Operational State' -c 'Usage State' -c 'VNFD ID'
+-------------------+--------------------------------------+
| Field | Value |
+-------------------+--------------------------------------+
| Onboarding State | ONBOARDED |
| Operational State | ENABLED |
| Usage State | NOT_IN_USE |
| VNFD ID | b1bb0ce7-ebca-4fa7-95ed-4840d7000003 |
+-------------------+--------------------------------------+
VNFD ID を環境変数として登録します。
export VNFD_ID=b1bb0ce7-ebca-4fa7-95ed-4840d7000003
CNF の作成
CNF を作成します。
default VIM が設定されていない場合、下記のように未定義のエラーが出てしまうため、設定します。
$ openstack vnflcm create $VNFD_ID
Default VIM is not defined.
$ openstack vim set --is-default True $VIM_ID
default VIM が設定されている場合は下記のように実行結果が表示されます。
$ openstack vnflcm create $VNFD_ID
+-----------------------------+------------------------------------------------------------------------------------------------------------------+
| Field | Value |
+-----------------------------+------------------------------------------------------------------------------------------------------------------+
| ID | 952a2324-0ea5-4831-af87-4d9549f7b35a |
| Instantiation State | NOT_INSTANTIATED |
| Links | { |
| | "self": { |
| | "href": "http://localhost:9890/vnflcm/v1/vnf_instances/952a2324-0ea5-4831-af87-4d9549f7b35a" |
| | }, |
| | "instantiate": { |
| | "href": "http://localhost:9890/vnflcm/v1/vnf_instances/952a2324-0ea5-4831-af87-4d9549f7b35a/instantiate" |
| | } |
| | } |
| VNF Configurable Properties | |
| VNF Instance Description | None |
| VNF Instance Name | vnf-952a2324-0ea5-4831-af87-4d9549f7b35a |
| VNF Product Name | Sample VNF |
| VNF Provider | Company |
| VNF Software Version | 1.0 |
| VNFD ID | b1bb0ce7-ebca-4fa7-95ed-4840d7000003 |
| VNFD Version | 1.0 |
| vnfPkgId | |
+-----------------------------+------------------------------------------------------------------------------------------------------------------+
環境変数として VNF INSTANCE ID を定義します。
export VNF_INSTANCE_ID=952a2324-0ea5-4831-af87-4d9549f7b35a
確認します。
$ openstack vnf package show $VNF_PACKAGE_ID \
-c 'Usage State'
+-------------+--------+
| Field | Value |
+-------------+--------+
| Usage State | IN_USE |
+-------------+--------+
$ openstack vnflcm show $VNF_INSTANCE_ID \
-c 'Instantiation State'
+---------------------+------------------+
| Field | Value |
+---------------------+------------------+
| Instantiation State | NOT_INSTANTIATED |
+---------------------+------------------+
CNF のインスタンス化
CNF をインスタンス化します。
リクエストパラメータファイルの作成
必要な情報を取得し、インスタンスリクエストに必要なパラメータファイルを作成します。
- vimConnectionInfo.vimId: e31459a6-1380-4fd8-930b-a70dc0500614
CNF をインスタンス化する VIM の ID を openstack vim list
コマンドで取得します。
このコマンドで複数の VIM が出力された場合は自身が使用したい VIM の ID を 1 つ選択してください。
今回は新たに登録した Kubernetes を指定するため、test-vim-k8s-kubeadm の ID を選択します。
$ openstack vim list
+--------------------------------------+----------------------+----------------------------------+------------+------------+-----------+
| ID | Name | Tenant_id | Type | Is Default | Status |
+--------------------------------------+----------------------+----------------------------------+------------+------------+-----------+
| e31459a6-1380-4fd8-930b-a70dc0500614 | test-vim-k8s-kubeadm | cd492cafc33c4d6b878ee570f6aeae21 | kubernetes | False | REACHABLE |
+--------------------------------------+----------------------+----------------------------------+------------+------------+-----------+
リクエストパラメータファイルを作成します。
additionalParamsには、Kubernetes リソース定義ファイルのパスが含まれています。
lcm-kubernetes-def-files がリストである必要があることに注意してください。
ユーザーは、リソースをデプロイする必要がある名前空間を指定することもできます。
cat << _EOF_ > ~/work/instance_kubernetes.json
{
"flavourId": "simple",
"additionalParams": {
"lcm-kubernetes-def-files": [
"Files/kubernetes/deployment.yaml"
],
"namespace": "default"
},
"vimConnectionInfo": [
{
"id": "8a3adb69-0784-43c7-833e-aab0b6ab4470",
"vimId": "e31459a6-1380-4fd8-930b-a70dc0500614",
"vimType": "kubernetes"
}
]
}
_EOF_
インスタンス化
CNF インスタンスをインスタンス化します。
$ openstack vnflcm instantiate $VNF_INSTANCE_ID instance_kubernetes.json
Instantiate request for VNF Instance 952a2324-0ea5-4831-af87-4d9549f7b35a has been accepted.
確認します。
インスタンス化状態が INSTANTIATED の場合、インスタンス化が成功したことを示します。
$ openstack vnflcm show $VNF_INSTANCE_ID -c 'Instantiation State'
+---------------------+--------------+
| Field | Value |
+---------------------+--------------+
| Instantiation State | INSTANTIATED |
+---------------------+--------------+
NOT_INSTANTIATED から変わりがない場合は openstack vnflcm op list
などのコマンドで経過を確認することもできます。
Operation State が PROCESSING の場合、処理中を意味します。
Kubernetes の Deployment 確認
コンテナ化された CNF がターゲットの Kubernetes VIM 環境で実行されていることを確認します。
このコマンドは Kubernetes Master ノードで実施します。
READY が1/1の場合、デプロイメントが正常に作成されたことを示します。
-A
オプションを付与することでどの名前空間上で動作しているかを確認することもできます。
$ kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
curry-probe-test001 1/1 1 1 2m28s
$ kubectl get deployment -A
NAMESPACE NAME READY UP-TO-DATE AVAILABLE AGE
calico-apiserver calico-apiserver 2/2 2 2 97m
calico-system calico-kube-controllers 1/1 1 1 101m
calico-system calico-typha 1/1 1 1 101m
default curry-probe-test001 1/1 1 1 2m37s
default nginx-deployment 2/2 2 2 94m
kube-system coredns 2/2 2 2 120m
tigera-operator tigera-operator 1/1 1 1 102m
発生したエラー
CNF がインスタンス化されない
下記のコマンド実行時のエラーです。
このエラーは Devstack インストール時、一緒にインストールされた Kubernetes を VIM として利用していた際に発生したエラーです。
$ openstack vnflcm instantiate $VNF_INSTANCE_ID instance_kubernetes.json
Failed to create resource
tacker-conductor[1171]: : kubernetes.client.exceptions.ApiException: (409)
tacker-conductor[1171]: 2022-07-13 01:12:51.559 ERROR tacker.vnflcm.vnflcm_driver [req-3a222d79-e537-4cb1-8722-33c1127deae8 admin admin] Unable to instantiate vnf instance f30d5550-99f4-45f5-93b9-8c84e0c56a2d due to error : Failed to create resource.: tacker.common.exceptions.CreateApiFalse: Failed to create resource.
tacker-conductor[1171]: 2022-07-13 01:12:51.560 ERROR root [req-3a222d79-e537-4cb1-8722-33c1127deae8 admin admin] Original exception being dropped: ['Traceback (most recent call last):\n', ' File "/opt/stack/tacker/tacker/vnfm/infra_drivers/kubernetes/k8s/translate_outputs.py", line 473, in deploy_k8s\n self._select_k8s_client_and_api(\n', ' File "/opt/stack/tacker/tacker/vnfm/infra_drivers/kubernetes/k8s/translate_outputs.py", line 400, in _select_k8s_client_and_api\n response = getattr(k8s_client_obj, self.method_value.get(kind))(\n', ' File "/usr/local/lib/python3.8/dist-packages/kubernetes/client/api/apps_v1_api.py", line 342, in create_namespaced_deployment\n return self.create_namespaced_deployment_with_http_info(namespace, body, **kwargs) # noqa: E501\n', ' File "/usr/local/lib/python3.8/dist-packages/kubernetes/client/api/apps_v1_api.py", line 437, in create_namespaced_deployment_with_http_info\n return self.api_client.call_api(\n', ' File "/usr/local/lib/python3.8/dist-packages/kubernetes/client/api_client.py", line 348, in call_api\n return self.__call_api(resource_path, method,\n', ' File "/usr/local/lib/python3.8/dist-packages/kubernetes/client/api_client.py", line 180, in __call_api\n response_data = self.request(\n', ' File "/usr/local/lib/python3.8/dist-packages/kubernetes/client/api_client.py", line 391, in request\n return self.rest_client.POST(url,\n', ' File "/usr/local/lib/python3.8/dist-packages/kubernetes/client/rest.py", line 275, in POST\n return self.request("POST", url,\n', ' File "/usr/local/lib/python3.8/dist-packages/kubernetes/client/rest.py", line 234, in request\n raise ApiException(http_resp=r)\n', 'kubernetes.client.exceptions.ApiException: (409)\nReason: Conflict\nHTTP response headers: HTTPHeaderDict({\'Audit-Id\': \'f779dfd4-2b9f-4745-9b0b-77e3c4a027e3\', \'Cache-Control\': \'no-cache, private\', \'Content-Type\': \'application/json\', \'X-Kubernetes-Pf-Flowschema-Uid\': \'278f6e23-4a3c-407d-a8d8-5865a79d827d\', \'X-Kubernetes-Pf-Prioritylevel-Uid\': \'109eaedd-4f4b-4c19-bd08-cc1a9c775c05\', \'Date\': \'Wed, 13
Content-Length\': \'250\'})\nHTTP response body: {"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"deployments.apps \\"curry-probe-test001\\" already exists","reason":"AlreadyExists","details":{"name":"curry-probe-test001","group":"apps","kind":"deployments"},"code":409}\n\n\n', '\nDuring handling of the above exception, another exception occurred:\n\n', 'Traceback (most recent call last):\n', ' File "/opt/stack/tacker/tacker/vnflcm/vnflcm_driver.py", line 371, in _instantiate_vnf\n instance_id = self._vnf_manager.invoke(\n', ' File "/opt/stack/tacker/tacker/common/driver_manager.py", line 71, in invoke\n return getattr(driver, method_name)(**kwargs)\n', ' File "/opt/stack/tacker/tacker/vnfm/infra_drivers/kubernetes/kubernetes_driver.py", line 1837, in instantiate_vnf\n k8s_objs = transformer.deploy_k8s(k8s_objs)\n', ' File "/opt/stack/tacker/tacker/vnfm/infra_drivers/kubernetes/k8s/translate_outputs.py", line 494, in deploy_k8s\n raise exceptions.CreateApiFalse(error=msg)\n', 'tacker.common.exceptions.CreateApiFalse: Failed to create resource.\n']: tacker.common.exceptions.VnfInstantiationFailed: Vnf instantiation failed for vnf f30d5550-99f4-45f5-93b9-8c84e0c56a2d, error: Failed to create resource.
tacker-conductor[1171]: 2022-07-13 01:12:51.560 DEBUG tacker.common.log [req-3a222d79-e537-4cb1-8722-33c1127deae8 admin admin] tacker.conductor.conductor_server.Conductor method _change_vnf_status called with arguments (<tacker.context.Context object at 0x7fb5d4844a90>, 'f30d5550-99f4-45f5-93b9-8c84e0c56a2d', ('ACTIVE', 'INACTIVE', 'ERROR', 'PENDING_INSTANTIATE', 'PENDING_CREATE', 'PENDING_UPDATE', 'PENDING_DELETE', 'PENDING_SCALE_IN', 'PENDING_SCALE_OUT', 'PENDING_HEAL', 'PENDING_TERMINATE', 'PENDING_CHANGE_EXT_CONN'), 'ERROR') {} from (pid=1171) wrapper /opt/stack/tacker/tacker/common/log.py:33
tacker-conductor[1171]: 2022-07-13 01:12:51.563 DEBUG tacker.conductor.conductor_server [req-3a222d79-e537-4cb1-8722-33c1127deae8 admin admin] Change status of vnf f30d5550-99f4-45f5-93b9-8c84e0c56a2d from PENDING_CREATE to ERROR from (pid=1171) _change_vnf_status /opt/stack/tacker/tacker/conductor/conductor_server.py:643
Failed to create resource.
など、原因はよくわからないですが、Kubernetes で正常に Pod が立ち上がっていないようでした。
VNF パッケージ内のマニフェストや Kubernetes 側に問題ありそうなので確認します。
Kubernetes disk-pressure で NoSchedule
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
curry-probe-test001-766bdd79bf-jwmlf 0/2 Pending 0 19h <none> <none> <none> <none>
$ kubectl get node
NAME STATUS ROLES AGE VERSION
yoshitest2 Ready <none> 5d23h v1.22.3
$ kubectl describe node yoshitest2
Name: yoshitest2
Roles: <none>
Labels: beta.kubernetes.io/arch=amd64
beta.kubernetes.io/os=linux
kubernetes.io/arch=amd64
kubernetes.io/hostname=yoshitest2
kubernetes.io/os=linux
Annotations: node.alpha.kubernetes.io/ttl: 0
volumes.kubernetes.io/controller-managed-attach-detach: true
CreationTimestamp: Thu, 07 Jul 2022 02:26:46 +0000
Taints: node.kubernetes.io/disk-pressure:NoSchedule
Unschedulable: false
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning EvictionThresholdMet 11m (x20720 over 2d11h) kubelet Attempting to reclaim ephemeral-storage
Warning FreeDiskSpaceFailed 83s (x718 over 2d11h) kubelet (combined from similar events): failed to garbage collect required amount of images. Wanted to free 8139422924 bytes, but freed 0 bytes
$ kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
default curry-probe-test001-766bdd79bf-jwmlf 0/2 Pending 0 19h
kube-system kube-apiserver-yoshitest2 1/1 Running 1 (5d23h ago) 5d23h
kube-system kube-controller-manager-yoshitest2 1/1 Running 1 (5d23h ago) 5d23h
kube-system kube-scheduler-yoshitest2 1/1 Running 1 (5d23h ago) 5d23h
Node や Pod の describe を確認すると、上記のような結果になりました。
node.kubernetes.io/disk-pressure
は Node のディスクが不足している場合に発生します。
そのため、ディスクの使用状況を確認します。
$ df -h
Filesystem Size Used Avail Use% Mounted on
udev 7.8G 0 7.8G 0% /dev
tmpfs 1.6G 2.1M 1.6G 1% /run
/dev/mapper/ubuntu--vg-ubuntu--lv 39G 37G 40M 100% /
tmpfs 7.9G 20K 7.9G 1% /dev/shm
...
確認すると使用率が 100% になっていたことがわかりました。
対応として 1 度マシンをシャットダウンし、 ESXi 上でディスクの割り当てを倍にしました。
networkPlugin cni failed to teardown pod
仮想マシンのディスクを拡張し、改めてインスタンス化を実行した際に発生したエラーです。
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
curry-probe-test001-766bdd79bf-jwmlf 0/2 ContainerCreating 0 22h <none> yoshitest2 <none> <none>
curry-probe-test001-766bdd79bf-xfgnf 0/2 ContainerCreating 0 58m <none> yoshitest2 <none> <none>
$ kubectl describe pod curry-probe-test001-766bdd79bf-jwmlf
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 158m (x1186 over 22h) default-scheduler 0/1 nodes are available: 1 node(s) had taint {node.kubernetes.io/disk-pressure: }, that the pod didn't tolerate.
Normal Scheduled 59m default-scheduler Successfully assigned default/curry-probe-test001-766bdd79bf-jwmlf to yoshitest2
Warning Evicted 56m (x5 over 59m) kubelet The node was low on resource: ephemeral-storage.
Warning ExceededGracePeriod 29m (x46 over 59m) kubelet Container runtime did not kill the pod within specified grace period.
Warning FailedKillPod 4m11s (x286 over 59m) kubelet error killing pod: failed to "KillPodSandbox" for "c17d2b89-7786-46d6-a005-7e866347517f" with KillPodSandboxError: "rpc error: code = Unknown desc = networkPlugin cni failed to teardown pod \"curry-probe-test001-766bdd79bf-jwmlf_default\" network: Looks like http://localhost:5036/delNetwork cannot be reached. Is kuryr-daemon running?; Post \"http://localhost:5036/delNetwork\": dial tcp 127.0.0.1:5036: connect: connection refused"
Is kuryr-daemon running?
となっており、kuryr-daemon が動作している? と書かれています。
また、localhost:5036/delNetwork cannot be reached
より、通信ができていないようです。
通常、Devstack インストールの stack.sh 実行時完了に kuryr-daemon は動作しているはずですが、動作していません。
現状態から kuryr-kubernetes を動作させるためのコマンドを実行し、動作するかを試します。
実行コマンドは正常に kuryr-kubernetes が動作している環境にて ps コマンドを使用して調べました。
$ /usr/bin/python3 /usr/local/bin/kuryr-k8s-controller --config-dir /etc/kuryr
INFO kuryr_kubernetes.config [-] Logging enabled!
INFO kuryr_kubernetes.config [-] /usr/local/bin/kuryr-k8s-controller version 6.0.1
CRITICAL kuryr-kubernetes [-] Unhandled error: KeyError: 'KUBERNETES_SERVICE_HOST'
ERROR kuryr-kubernetes Traceback (most recent call last):
ERROR kuryr-kubernetes File "/usr/local/bin/kuryr-k8s-controller", line 10, in <module>
ERROR kuryr-kubernetes sys.exit(start())
ERROR kuryr-kubernetes File "/opt/stack/kuryr-kubernetes/kuryr_kubernetes/controller/service.py", line 180, in start
ERROR kuryr-kubernetes clients.setup_clients()
ERROR kuryr-kubernetes File "/opt/stack/kuryr-kubernetes/kuryr_kubernetes/clients.py", line 62, in setup_clients
ERROR kuryr-kubernetes setup_kubernetes_client()
ERROR kuryr-kubernetes File "/opt/stack/kuryr-kubernetes/kuryr_kubernetes/clients.py", line 72, in setup_kubernetes_client
ERROR kuryr-kubernetes host = os.environ['KUBERNETES_SERVICE_HOST']
ERROR kuryr-kubernetes File "/usr/lib/python3.8/os.py", line 675, in __getitem__
ERROR kuryr-kubernetes raise KeyError(key) from None
ERROR kuryr-kubernetes KeyError: 'KUBERNETES_SERVICE_HOST'
Unhandled error: KeyError: 'KUBERNETES_SERVICE_HOST'
となっています。
KUBERNETES_SERVICE_HOST とは API を利用するための外向きのアドレスです。
.kube/config にこの情報が記録されています。
同様に KUBERNETES_SERVICE_PORT_HTTPS
も設定しなければ同様のエラーが発生するため、定義します。
$ export KUBERNETES_SERVICE_HOST=10.100.2.220
$ export KUBERNETES_SERVICE_PORT_HTTPS=6443
定義後、再度コマンドを実行します。
$ /usr/bin/python3 /usr/local/bin/kuryr-k8s-controller --config-dir /etc/kuryr
INFO kuryr_kubernetes.config [-] Logging enabled!
INFO kuryr_kubernetes.config [-] /usr/local/bin/kuryr-k8s-controller version 6.0.1
CRITICAL kuryr-kubernetes [-] Unhandled error: RuntimeError: Unable to find token_file : /var/run/secrets/kubernetes.io/serviceaccount/token
ERROR kuryr-kubernetes Traceback (most recent call last):
ERROR kuryr-kubernetes File "/usr/local/bin/kuryr-k8s-controller", line 10, in <module>
ERROR kuryr-kubernetes sys.exit(start())
ERROR kuryr-kubernetes File "/opt/stack/kuryr-kubernetes/kuryr_kubernetes/controller/service.py", line 180, in start
ERROR kuryr-kubernetes clients.setup_clients()
ERROR kuryr-kubernetes File "/opt/stack/kuryr-kubernetes/kuryr_kubernetes/clients.py", line 62, in setup_clients
ERROR kuryr-kubernetes setup_kubernetes_client()
ERROR kuryr-kubernetes File "/opt/stack/kuryr-kubernetes/kuryr_kubernetes/clients.py", line 82, in setup_kubernetes_client
ERROR kuryr-kubernetes _clients[_KUBERNETES_CLIENT] = k8s_client.K8sClient(api_root)
ERROR kuryr-kubernetes File "/opt/stack/kuryr-kubernetes/kuryr_kubernetes/k8s_client.py", line 66, in __init__
ERROR kuryr-kubernetes raise RuntimeError(
ERROR kuryr-kubernetes RuntimeError: Unable to find token_file : /var/run/secrets/kubernetes.io/serviceaccount/token
正常な環境であれば /var/run/secrets/kubernetes.io/serviceaccount/
があるそうですが、エラーが発生している本環境では /var/run
までしかありませんでした。
次に kuryr-kubernetes 系のサービスが復活できるかを試しました。
下記のサイトで Kuryr サービスが Kubernetes network アドオンとしてインストールされていることがわかりました。
stack.sh では下記のコマンドで kuryr-kubernetes をインストールしているようです。
source /opt/stack/kuryr-kubernetes/devstack/plugin.sh stack pre-install
source /opt/stack/kuryr-kubernetes/devstack/plugin.sh stack install
source /opt/stack/kuryr-kubernetes/devstack/plugin.sh stack post-config
source /opt/stack/kuryr-kubernetes/devstack/plugin.sh stack extra
source /opt/stack/kuryr-kubernetes/devstack/plugin.sh stack test-config
上記のコマンド実行しましたが、$DEST などの様々な環境変数が解決できず、not found エラーが発生しました。
DevStack ではアンインストール用のスクリプトとして unstack.sh が提供されています。
また、ローカルリポジトリを含め完全削除するためには clean.sh スクリプトが提供されています。
この 2 つのスクリプト実行後に stack.sh やり直しました。
$ ./unstack.sh
$ ./clean.sh
$ ./stack.sh
...
[Call Trace]
./stack.sh:1282:start_ovn_services
/opt/stack/devstack/lib/neutron-legacy:519:start_ovn
/opt/stack/devstack/lib/neutron_plugins/ovn_agent:700:wait_for_sock_file
/opt/stack/devstack/lib/neutron_plugins/ovn_agent:178:die
[ERROR] /opt/stack/devstack/lib/neutron_plugins/ovn_agent:178 Socket /var/run/openvswitch/ovnnb_db.sock not found
Error on exit
unstack.sh と clean.sh では初回インストール時に設定されたネットワークの設定が削除されません。
そのため、2 回目以降のインストール時に不整合が生じ、エラーとなっているようです。
対応として、環境を作成し直し、再度 stack.sh スクリプトを実行します。
結果として、kuryr-kubernetes が動作しませんでした。
stack@yoshitest:~/devstack$ kubectl get pod --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system kube-apiserver-yoshitest 1/1 Running 1 (3m26s ago) 28s
kube-system kube-controller-manager-yoshitest 1/1 Running 1 (3m26s ago) 51s
kube-system kube-scheduler-yoshitest 1/1 Running 1 (3m26s ago) 50s
stack@yoshitest:~/devstack$ ps aux |grep kuryr
stack 14446 0.0 0.0 6384 2472 pts/0 S+ 07:33 0:00 grep --color=auto kuryr
docker images
コマンドで Docker イメージがプルされていることは確認できました。
しかし、docker ps
コマンドで確認すると、起動している様子はありませんでした。
$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
kuryr/cni latest d5eef84bb247 2 hours ago 1.28GB
<none> <none> 29ba6174d4c5 2 hours ago 883MB
kuryr/controller latest d0868ab345af 2 hours ago 1.06GB
k8s.gcr.io/kube-apiserver v1.22.12 d922296a8b85 17 hours ago 128MB
k8s.gcr.io/kube-scheduler v1.22.12 5ee90014579c 17 hours ago 52.7MB
k8s.gcr.io/kube-controller-manager v1.22.12 f5ef4d6e36ee 17 hours ago 122MB
k8s.gcr.io/kube-proxy v1.22.12 761817698b62 17 hours ago 104MB
quay.io/centos/centos stream8 f8a44dfb7278 4 weeks ago 339MB
k8s.gcr.io/etcd 3.5.0-0 004811815584 13 months ago 295MB
k8s.gcr.io/coredns/coredns v1.8.4 8d147537fb7d 13 months ago 47.6MB
quay.io/kuryr/golang 1.16 d5dc529b0ee7 14 months ago 862MB
k8s.gcr.io/pause 3.5 ed210e3e4a5b 16 months ago 683kB
$ sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
728597d87b27 k8s.gcr.io/pause:3.5 "/pause" 10 minutes ago Exited (0) 10 minutes ago k8s_POD_nginx-deployment-66b6c48dd5-pdlws_default_e2c38d0e-6dbf-40fd-8c9a-c6a5a5b17514_0
ad3c146a8c38 k8s.gcr.io/pause:3.5 "/pause" 10 minutes ago Exited (0) 10 minutes ago k8s_POD_nginx-deployment-66b6c48dd5-msvcp_default_3ec4a739-b003-4420-928d-09ceeab5c3ba_0
8e465e2810ab 5ee90014579c "kube-scheduler --au…" 37 minutes ago Up 37 minutes k8s_kube-scheduler_kube-scheduler-yoshitest_kube-system_acb57d0b7dff68b61cfe45619134da6c_1
e6bddd398239 d922296a8b85 "kube-apiserver --ad…" 37 minutes ago Up 37 minutes k8s_kube-apiserver_kube-apiserver-yoshitest_kube-system_83bd29bbe6554e93295c44ac4a1ffb04_1
a14ae872f42d f5ef4d6e36ee "kube-controller-man…" 37 minutes ago Up 37 minutes k8s_kube-controller-manager_kube-controller-manager-yoshitest_kube-system_badbf50c21b4819f89f3693e164f4804_1
6d50fd7b9147 k8s.gcr.io/pause:3.5 "/pause" 37 minutes ago Up 37 minutes k8s_POD_kube-controller-manager-yoshitest_kube-system_badbf50c21b4819f89f3693e164f4804_1
0fb02e37c808 k8s.gcr.io/pause:3.5 "/pause" 37 minutes ago Up 37 minutes k8s_POD_kube-apiserver-yoshitest_kube-system_83bd29bbe6554e93295c44ac4a1ffb04_1
008e41fb4f9b k8s.gcr.io/pause:3.5 "/pause" 37 minutes ago Up 37 minutes k8s_POD_kube-scheduler-yoshitest_kube-system_acb57d0b7dff68b61cfe45619134da6c_1
aa681ca00be7 f5ef4d6e36ee "kube-controller-man…" 2 hours ago Exited (255) 38 minutes ago k8s_kube-controller-manager_kube-controller-manager-yoshitest_kube-system_badbf50c21b4819f89f3693e164f4804_0
2b904fbf4145 5ee90014579c "kube-scheduler --au…" 2 hours ago Exited (255) 38 minutes ago k8s_kube-scheduler_kube-scheduler-yoshitest_kube-system_acb57d0b7dff68b61cfe45619134da6c_0
1f8929b099c6 d922296a8b85 "kube-apiserver --ad…" 2 hours ago Exited (255) 38 minutes ago k8s_kube-apiserver_kube-apiserver-yoshitest_kube-system_83bd29bbe6554e93295c44ac4a1ffb04_0
9447e7c252f8 k8s.gcr.io/pause:3.5 "/pause" 2 hours ago Exited (255) 38 minutes ago k8s_POD_kube-scheduler-yoshitest_kube-system_acb57d0b7dff68b61cfe45619134da6c_0
ca6f69e6faf7 k8s.gcr.io/pause:3.5 "/pause" 2 hours ago Exited (255) 38 minutes ago k8s_POD_kube-controller-manager-yoshitest_kube-system_badbf50c21b4819f89f3693e164f4804_0
3abbfee59682 k8s.gcr.io/pause:3.5 "/pause" 2 hours ago Exited (255) 38 minutes ago k8s_POD_kube-apiserver-yoshitest_kube-system_83bd29bbe6554e93295c44ac4a1ffb04_0
本環境で kuryr-kubernetes 系のサービスが動作しない原因は不明です。
kuryr-kubernetes は OpenStack と Kubernetes を同じ Neutron ネットワークで接続するためのサービスです。
これは Devstack の Kubernetes で CNI の役割を果たします。
そのため、kuryr-kubernetes が動作しなければ新規の Pod を立てることができません。
Kubernetes は CNI として kuryr-kubernetes を使用する必要はなく、Calico などを使用できます。
しかし、Devstack の Kubernetes では kuryr-kubernetes プラグインをインストールしなければ Kubernetes がインストールされません。
そのため、別途 Kubernetes 環境を準備し、VIM として使用します。
3. インストール手順 のように kubeadm で Kubernetes をインストールし、VIM として登録して利用したところ VNF として Pod を立てることができました。
Kubernetes インストールできない
Kubernetes インストール時に発生したエラーです。
tcp 127.0.0.1:10248: connect: connection refused
下記のコマンド実行時のエラーです。
$ sudo kubeadm init --pod-network-cidr=10.244.0.0/16
本環境のエラーログの記録をしておりませんでしたが、kubeadmを用いたKubernetes再インストールに失敗する] のエラーと同様のエラーが発生しました。
本環境の Docker の driver を確認します。
$ docker info | grep Cgroup
Cgroup Driver: cgroupfs
Cgroup Version: 1
下記を追記し、daemon のリロードと docker.service の再起動を行います。
$ vim /etc/docker/daemon.json
・・・
"exec-opts": ["native.cgroupdriver=systemd"],
・・・
$ systemctl daemon-reload
$ systemctl restart docker
$ docker info | grep Cgroup
Cgroup Driver: systemd
Cgroup Version: 1
この状態で再度 sudo kubeadm init --pod-network-cidr=10.244.0.0/16
を実行したところ、無事に完了しました。
sample.yaml が起動しない
下記のコマンド実行時のエラーです。
kubectl apply -f sample.yaml
nginx-deployment-66b6c48dd5-glcrt は本環境で立ち上がった Pod を指定してください。
kubectl get pod
コマンドで調べることができます。
$ kubectl describe pod nginx-deployment-66b6c48dd5-glcrt
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 1s (x3 over 2m44s) default-scheduler 0/1 nodes are available: 1 node(s) had taint {node-role.kubernetes.io/master: }, that the pod didn't tolerate.
Master ノードには node-role.kubernetes.io/master:NoSchedule という Taints が設定されているため、Pod が展開されません。
そのため、この Taint 情報を外す必要があります。
$ kubectl describe node yoshitest
...
Taints: node-role.kubernetes.io/master:NoSchedule
Taint 情報を外します。
kubectl taint nodes yoshitest node-role.kubernetes.io/master:NoSchedule-
node/master untainted
まとめ
kuryr-kubernetes が再起動時に動作しないため、DevStack の Kubernetes を使用できなかったです。
Vagrant を使用して DevStack を起動した場合は再起動等で停止することはないそうですが、自分は試してないのでわからないです。
自分も試したいです。
ここまでお読みいただき、ありがとうございました。