Если вы хотите выполнить вторичную разработку для K8S или инкапсулировать некоторые функции на исходной основе, чтобы разработчикам было проще их использовать, вам необходимо освоить использование оператора.
Я думаю Operator Действительно K8S Дизайн расширения очень продуманный. Оно похоже на подключаемую систему. Как только оно у вас появится, вы почувствуете, что оно у вас есть. k8s Расширенное право на эксплуатацию может расширить различные виды использования. Это Что такое оператор Шерстяная ткань? Это требует CRD Кстати.
Прежде всего нам нужно знать, что первая концепция CRD(Custom Resource Define)
,Пользовательское определение ресурса,Судя по названию, этоиспользоватьможет пройти CRD для создания пользовательских ресурсов. мы знаем в K8S Существуют различные ресурсы в Pod
、Deployment
、StatefulSet
… Письмо yaml
Соответствующий тип ресурса будет указан при вводе файла.
Официальная документация:Create a CustomResourceDefinition Существует фактическое CustomResourceDefinition Случай
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
# name must match the spec fields below, and be in the form: <plural>.<group>
name: crontabs.stable.example.com
spec:
# group name to use for REST API: /apis/<group>/<version>
group: stable.example.com
# list of versions supported by this CustomResourceDefinition
versions:
- name: v1
# Each version can be enabled/disabled by Served flag.
served: true
# One and only one version must be marked as the storage version.
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
cronSpec:
type: string
image:
type: string
replicas:
type: integer
# either Namespaced or Cluster
scope: Namespaced
names:
# plural name to be used in the URL: /apis/<group>/<version>/<plural>
plural: crontabs
# singular name to be used as an alias on the CLI and for display
singular: crontab
# kind is normally the CamelCased singular type. Your resource manifests use this.
kind: CronTab
# shortNames allow shorter string to match your resource on the CLI
shortNames:
- ct
---- Ниже приводится конкретная информация object ----
apiVersion: "stable.example.com/v1"
kind: CronTab
metadata:
name: my-new-cron-object
spec:
cronSpec: "* * * * */5"
image: my-awesome-cron-image
Затем, с помощью этого, вы можете управлять pod
Вы можете управлять определенным вами объектом таким же образом, а также определить для него некоторые необходимые свойства. Тогда есть CRD После этого у нас появляется очень мощная способность расширять k8s существующий функционал. Но одного этого недостаточно. Потому что он определяет только те ресурсы, которые вам нужны, но как этим ресурсом управлять?
Определенно невозможно иметь ресурсы без того, чтобы кто-то ими управлял, поэтому нам нужен контроллер, чтобы контролировать его поведение и действия. Фактически, контроллер — это, по сути, контур управления. Мы знаем, что режим управления k8s на самом деле основан на модели состояния. Он будет отслеживать состояние всех ресурсов. Когда текущий статус ресурса не соответствует состоянию ресурса, определенному пользователем, он будет вносить коррективы и находить способы корректировки. состояние ресурсов до ожидаемого значения.
for {
действительныйсостояние := получатькластерсерединаобъект X издействительныйсостояние(Actual State)
ожидатьсостояние := получатькластерсерединаобъект X изожидатьсостояние(Expectation State)
if действительныйсостояние == ожидатьсостояние{ ничего не делать
} else {
Выполнять хореографические действия, которые приводят фактическое состояние в желаемое состояние.
}
}
Когда диспетчер контроллера обнаруживает, что фактическое состояние ресурса отличается от ожидаемого, он запускает обработчик событий, зарегистрированный соответствующим контроллером, чтобы позволить ему выполнить настройку в соответствии с характеристиками самого ресурса.
Поэтому мы можем просто понимать это как Operator = CRD + Controller Другими словами, пользовательские ресурсы плюс пользовательские контроллеры Оператор, с помощью которого мы можем не только настраивать нужные нам ресурсы, но и управлять ими с помощью желаемой логики и метода.
Тогда вы можете себе представить, насколько он универсален. Например: с помощью пользовательских ресурсов вы можете определить различные атрибуты, которые вам нужны. В исходном развертывании были только эти атрибуты. Теперь вы можете расширить различные атрибуты, которые хотите, и объединить некоторые существующие ресурсы. В то же время с помощью специального контроллера вы можете выполнять любую операцию. Самое главное, что вы можете сразу знать, когда необходимо запланировать различные ситуации (перезапуск, аварийный выход и т. д.), и вы можете контролировать, как идти. к планированию, какие свойства следует настроить после планирования и т. д.
Тогда эта статья поможет вам быстро создать демо-версию, чтобы познакомиться с Оператором. Конечно, предполагается, что вам нужна работоспособная среда k8s.
развивать Operator Нет необходимости использовать kubebuilder Также доступен https://github.com/operator-framework/operator-sdk Я больше привык использовать kubebuilder Вот и все
Установить См. документацию:installation
$ curl -L -o kubebuilder "https://go.kubebuilder.io/dl/latest/$(go env GOOS)/$(go env GOARCH)"
$ chmod +x kubebuilder && mv kubebuilder /usr/local/bin/
$ mkdir opex
$ cd opex
$ kubebuilder init --domain linkinstars.com --repo linkinstars.com/op-ex
$ kubebuilder create api --group example --version v1 --kind ExampleA
# Затем введите дважды y
Create Resource [y/n]
y
Create Controller [y/n]
y
Writing kustomize manifests for you to edit...
Writing scaffold for you to edit...
api/v1/examplea_types.go
api/v1/groupversion_info.go
internal/controller/suite_test.go
internal/controller/examplea_controller.go
...
...
Шаблон CRD-контроллера. Вы можете начать с беглого просмотра структуры проекта. Далее мы начнем работать над кодированием.
Во-первых, давайте проясним нашу цель. Наша цель — создать CRD и Контроллер для взаимодействия с Оператором. Созданный нами на этот раз CRD играет роль монитора. Когда объект с меткой (Label) с указанным именем появится во всем кластере, монитор изменит свой статус и станет контролируемым.
Исправлять api/v1/examplea_types.go
документ
package v1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// ExampleASpec defines the desired state of ExampleA
type ExampleASpec struct {
GroupName string `json:"groupName,omitempty"`
}
// ExampleAStatus defines the observed state of ExampleA
type ExampleAStatus struct {
UnderControl bool `json:"underControl,omitempty"`
}
//+kubebuilder:object:root=true
//+kubebuilder:subresource:status
// ExampleA is the Schema for the examplea API
type ExampleA struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec ExampleASpec `json:"spec,omitempty"`
Status ExampleAStatus `json:"status,omitempty"`
}
//+kubebuilder:object:root=true
// ExampleAList contains a list of ExampleA
type ExampleAList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []ExampleA `json:"items"`
}
func init() {
SchemeBuilder.Register(&ExampleA{}, &ExampleAList{})
}
Вы можете видеть, что здесь мы в основном определяем ExampleA
из Spec
,То есть мы часто yaml
документсередина Писатьиз spec
свойства, куда мы добавили GroupName
То есть имя группы.
Исправлять internal/controller/examplea_controller.go
package controller
import (
"context"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
examplev1 "linkinstars.com/op-ex/api/v1"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
)
// ExampleAReconciler reconciles a ExampleA object
type ExampleAReconciler struct {
client.Client
Scheme *runtime.Scheme
}
//+kubebuilder:rbac:groups=example.linkinstars.com,resources=examplea,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=example.linkinstars.com,resources=examplea/status,verbs=get;update;patch
//+kubebuilder:rbac:groups=example.linkinstars.com,resources=examplea/finalizers,verbs=update
// Reconcile
func (r *ExampleAReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
logger := log.FromContext(ctx)
logger.Info("Начать вызов метода Reconcile")
var exp examplev1.ExampleA
if err := r.Get(ctx, req.NamespacedName, &exp); err != nil {
logger.Error(err, "Соответствующий ресурс изCRD не найден")
return ctrl.Result{}, client.IgnoreNotFound(err)
}
exp.Status.UnderControl = false
var podList corev1.PodList
if err := r.List(ctx, &podList); err != nil {
logger.Error(err, «Невозможно получить список модулей»).
} else {
for _, item := range podList.Items {
if item.GetLabels()["group"] == exp.Spec.GroupName {
logger.Info("Найти соответствующий ресурс изпода", "name", item.GetName())
exp.Status.UnderControl = true
}
}
}
if err := r.Status().Update(ctx, &exp); err != nil {
logger.Error(err, «Невозможно обновить состояние ресурса CRD»)
return ctrl.Result{}, err
}
logger.Info("Состояние ресурса CRD обновлено", "status", exp.Status.UnderControl)
return ctrl.Result{}, nil
}
// SetupWithManager sets up the controller with the Manager.
func (r *ExampleAReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&examplev1.ExampleA{}).
Watches(
&corev1.Pod{},
handler.EnqueueRequestsFromMapFunc(r.podChangeHandler),
).
Complete(r)
}
func (r *ExampleAReconciler) podChangeHandler(ctx context.Context, obj client.Object) []reconcile.Request {
logger := log.FromContext(ctx)
var req []reconcile.Request
var list examplev1.ExampleAList
if err := r.Client.List(ctx, &list); err != nil {
logger.Error(err, «Невозможно получить ресурс»)
} else {
for _, item := range list.Items {
if item.Spec.GroupName == obj.GetLabels()["group"] {
req = append(req, reconcile.Request{
NamespacedName: types.NamespacedName{Name: item.Name, Namespace: item.Namespace},
})
}
}
}
return req
}
Основная логика очень проста,Просто пройди все из капсула, если найдется label с соответствующими groupName из pod Сразу Исправлятькогдавперед crd из UnderControl Статус true
if item.GetLabels()["group"] == exp.Spec.GroupName {
logger.Info("Найти соответствующий ресурс изпода", "name", item.GetName())
exp.Status.UnderControl = true
}
Есть несколько ключевых моментов
Watches
Первый параметр метода — тип мониторизобъекта, второй параметр — handler。использовать kubebuilder Из удобства означает, что развертываниеотлаживать очень удобно. Есть шаблоны. Выполните следующую команду, чтобы сгенерировать и. CRD Установитьприезжать k8s в кластере.
$ make manifests
$ make install
После успешного завершения установки проверьте это.
$ kubectl get crds |grep linkin
exampleas.example.linkinstars.com 2023-08-03T23:02:39Z
error: accumulating resources: accumulation err='accumulating resources from 'bases/example.linkinstars.com_examplea.yaml'
Если возникает ошибка, подобная этой,Обычно возникает из-за проблем с генерацией названий документов из,Исправлять config/crd/kustomization.yaml
документсерединаиз resources:
для - bases/example.linkinstars.com_exampleas.yaml
Соответствует правильному имени
Для запуска рекомендуется открыть новое окно терминала.,Он запустится в терминале и введет соответствующее избревно.,Удобен для последующего просмотра
$ make run
2023-08-03T23:07:21+08:00 INFO controller-runtime.metrics Metrics server is starting to listen {"addr": ":8080"}
2023-08-03T23:07:21+08:00 INFO setup starting manager
2023-08-03T23:07:21+08:00 INFO starting server {"path": "/metrics", "kind": "metrics", "addr": "[::]:8080"}
2023-08-03T23:07:21+08:00 INFO Starting server {"kind": "health probe", "addr": "[::]:8081"}
2023-08-03T23:07:21+08:00 INFO Starting EventSource {"controller": "examplea", "controllerGroup": "example.linkinstars.com", "controllerKind": "ExampleA", "source": "kind source: *v1.ExampleA"}
2023-08-03T23:07:21+08:00 INFO Starting EventSource {"controller": "examplea", "controllerGroup": "example.linkinstars.com", "controllerKind": "ExampleA", "source": "kind source: *v1.Pod"}
2023-08-03T23:07:21+08:00 INFO Starting Controller {"controller": "examplea", "controllerGroup": "example.linkinstars.com", "controllerKind": "ExampleA"}
2023-08-03T23:07:21+08:00 INFO Starting workers {"controller": "examplea", "controllerGroup": "example.linkinstars.com", "controllerKind": "ExampleA", "worker count": 1}
2023-08-03T23:08:46+08:00 INFO Начните вызывать метод Reconcile {"controller": "examplea", "controllerGroup": "example.linkinstars.com", "controllerKind": "ExampleA", "ExampleA": {"name":"my-opex","namespace":"default"}, "namespace": "default", "name": "my-opex", "reconcileID": "9a03fe8e-8461-4500-b32f-140161095f8b"}
2023-08-03T23:08:46+08:00 INFO Обновлено состояние ресурса CRD. {"controller": "examplea", "controllerGroup": "example.linkinstars.com", "controllerKind": "ExampleA", "ExampleA": {"name":"my-opex","namespace":"default"}, "namespace": "default", "name": "my-opex", "reconcileID": "9a03fe8e-8461-4500-b32f-140161095f8b", "status": false}
Создайте CRD config/samples/example_v1_examplea.yaml
Содержание следующее, уточняйте groupName для business То есть, когда появится business из pod этот crd Мы начали внимательно следить.
apiVersion: example.linkinstars.com/v1
kind: ExampleA
metadata:
labels:
app.kubernetes.io/name: examplea
app.kubernetes.io/instance: examplea-sample
app.kubernetes.io/part-of: opex
app.kubernetes.io/managed-by: kustomize
app.kubernetes.io/created-by: opex
name: my-opex
spec:
groupName: business
kubectl apply -f config/samples/example_v1_examplea.yaml
Затем,Давайте проверим состояние бывшего CRD.,Вы можете видеть, что теперь состояние должно быть пустым.
$ kubectl describe ExampleA my-opex
Затем Создать новыйдокумент example_v1_examplea 1.yaml
apiVersion: v1
kind: Pod
metadata:
name: busybox
labels:
group: "business"
spec:
containers:
- name: busybox
image: busybox:latest
command:
- sleep
- "3600"
Затем еще раз проверьте статус CRD.
$ kubectl describe ExampleA my-opex
...
Spec:
Group Name: business
Status:
Under Control: true
Events: <none>
...
Вы можете видеть, что статус управления теперь изменился на истинный, а также вы можете увидеть неожиданное изменение состояния ресурса в консоли.
2023-08-03T23:28:21+08:00 INFO Начните вызывать метод Reconcile {"controller": "examplea", "controllerGroup": "example.linkinstars.com", "controllerKind": "ExampleA", "ExampleA": {"name":"my-opex","namespace":"default"}, "namespace": "default", "name": "my-opex", "reconcileID": "7578ca2f-2bfe-4e4b-ba1c-3d43ff366ddf"}
2023-08-03T23:28:21+08:00 INFO Обновлено состояние ресурса CRD. {"controller": "examplea", "controllerGroup": "example.linkinstars.com", "controllerKind": "ExampleA", "ExampleA": {"name":"my-opex","namespace":"default"}, "namespace": "default", "name": "my-opex", "reconcileID": "7578ca2f-2bfe-4e4b-ba1c-3d43ff366ddf", "status": false}
2023-08-03T23:28:21+08:00 INFO Начните вызывать метод Reconcile {"controller": "examplea", "controllerGroup": "example.linkinstars.com", "controllerKind": "ExampleA", "ExampleA": {"name":"my-opex","namespace":"default"}, "namespace": "default", "name": "my-opex", "reconcileID": "e37ac2a6-a769-491c-9d73-e89ea8e43f23"}
2023-08-03T23:28:21+08:00 INFO Обновлено состояние ресурса CRD. {"controller": "examplea", "controllerGroup": "example.linkinstars.com", "controllerKind": "ExampleA", "ExampleA": {"name":"my-opex","namespace":"default"}, "namespace": "default", "name": "my-opex", "reconcileID": "e37ac2a6-a769-491c-9d73-e89ea8e43f23", "status": false}
До сих пор,Наша первоначальная работа завершена. После этого вы сможете изучить более сложные и разнообразные операции.,Удовлетворение различных потребностей на основе конкретных фактических требований бизнес-сценария.
Если вам нужно сначала переработать и удалить соответствующие ресурсы, сначала kubectl delete -f
Удалите все созданные тесты. Затем выполните его напрямую make uninstall
Вот и все.
В Интернете много для руля и Operator изаналогия, на самом деле Я Думаю, эти два направления разные. шлем Это значит собрать все необходимые ресурсы для развертывания вместе, чтобы облегчить упаковку. когдаран CRD Подобные функции также могут быть реализованы и являются более мощными. но helm Ресурс уже есть в коллекции, в большинстве случаев развертывается. k8s Предоставить из deploy/service/… Ожидания достаточно. Самое главное, руль Не могу контролировать цикл, контроллер. Вот и все Operator из души.
Я думаю, многие люди узнают Operator Сложный или трудный в использовании, большинство людей этого не понимают. k8s Внутренние принципы приводят к из. Если ты его очень хорошо знаешь Controller Manager из принципа и для, до контура управления, по сути Operator Он был очень хорошо упакован. Дизайн такой Думаю, причина в том, что очень удобно расширяться.
kubebuilder Есть еще один официальный CronJob из учебника, позволит вам быстро использовать Operator реализовать CronJob из Функция。Я Новичкам все еще может быть немного сложно думать для, но после того, как вы прочтете эту статью и попрактикуетесь в ней, я предлагаю вам поиграть, и понять будет легче.