Un.、OperatorIntroduction
InKubernetesNous utilisons souventDeployment、DaemonSet、Service、ConfigMapAutres ressources,Ces ressources sontKubernetesRessources intégrées pour,Leur création、Mise à jour、Supprimer, etc. tousController ManagerResponsable de la gestion.
2.、OperatorComposition
Operator(Controller+CRD),OperatorC'est parKubernetesRessources personnalisées(CRD)Et le Contrôleur(Controller)Services d'extension méta - native constitués,Parmi euxCRDChaqueOperatorObjets de ressources personnalisés à créer et à gérer,Le rez - de - chaussée passe parAPIServerL'interface estETCDEnregistrer un nouveau type de ressource dans,Une fois l'inscription terminée, vous pouvez créer des objets pour ce type de ressource.Mais il n'est pas pratique d'enregistrer uniquement les ressources et de créer des objets de ressources,CRDLe plus important, c'est qu'il faut faire correspondreControllerPour réaliser la fonctionnalité de la ressource personnalisée pour atteindre l'état désiré de la ressource personnalisée,Par exemple, intégréDeployment ControllerPour contrôlerDepartmentFonction de l'objet ressource,Générer une quantité spécifique dePodSurveiller son état,Et agir en conséquence en fonction de l'événement.
Trois、OperatorUtiliser
L'utilisateur veut construire unKubernetes Operator, Il y a beaucoup d'outils à choisir, comme Operator SDK、Kubebuilder,On peut même utiliserOperator SDK(HELM、Ansible、Go). Ces outils créent Kubernetes Operator Utilisé pour surveiller les ressources personnalisées , Et ajuster l'état des ressources en fonction de l'évolution des ressources .
Operator En tant que ressource d'extension personnalisée pour Deployment Pour déployer KubernetesMoyenne,AdoptionList-Watch Comment écouter les changements de ressources correspondantes , Lorsque l'utilisateur modifie quelque chose dans une ressource personnalisée ,Operator Surveille les changements de ressources , Et effectuer des actions spécifiques en fonction des changements , Ces actions sont généralement Kubernetes API Certaines ressources sont appelées .
Quatre、OperatorCas d'application
KubebuilderIntroduction
KubebuilderC'est utile.GoConstruction linguistiqueKubenetes APIContrôleur etCRDOutils d'échafaudage pour,En utilisantKubebuilder, Les utilisateurs peuvent suivre un cadre de programmation simple ,CompilationOperatorExemples d'utilisation.
- kubenetes: v1.23.8
- go
tar xf go1.18.3.linux-amd64.tar.gz
mv go /usr/local/
vim /etc/profile.d/go183.sh
export GO111MODULE=on
export GOROOT=/usr/local/go
export GOPATH=/root/gopath
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
source /etc/profile.d/go183.sh
- kubebuilder: 3.5.0
yum -y install gcc
curl -L -o kubebuilder https://go.kubebuilder.io/dl/latest/$(go env GOOS)/$(go env GOARCH)
chmod +x kubebuilder && mv kubebuilder /usr/local/bin/
kubebuilder version
CAS
Welcome Cas principalement mis en œuvre OperatorEtCRD Déployer un ensemble complet d'environnements d'application , Vous pouvez créer des ressources basées sur des types personnalisés ,En créant unWelcomeType de ressource, Création automatique de fond DeploymentEtService,AdoptionWebAccès à la pageService Déploiement de l'application de rendu , Gestion du contrôle par un contrôleur personnalisé
Création de notre médecine occidentale Welcome Ressources personnalisées et Controllers, Finalement, nous pouvons passer par un code similaire à YAML Déploiement de fichiers simple WebApplication
apiVersion: webapp.demo.welcome.domain/v1
kind: Welcome
metadata:
name: welcome-sample
spec:
name: myfriends
WebIntroduction à l'application
Dans ce cas,Nous utilisonsGoLanguesHTTPLe module crée unWebServices, L'utilisateur charge automatiquement après avoir accédé à la page NAMEEtPORT Variables d'environnement et rendu index.htmlDans un fichier statique,Les codes sont les suivants::
package main
import (
"fmt"
"net/http"
"os"
)
func main() {
name := os.Getenv("NAME")
hello := fmt.Sprintf("Hello %s", name)
http.Handle("/hello/", http.StripPrefix("/hello/", http.FileServer(http.Dir("static"))))
f, err := os.OpenFile("./static/index.html", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
if err != nil {
panic(err)
}
defer f.Close()
if _, err = f.WriteString(hello); err != nil {
panic(err)
}
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
}
Parmi eux,NAME Les variables d'environnement passent par WelcomeDéfini dansnameChamp obtenir, Nous Détaillons la façon d'obtenir les champs dans la rédaction du Contrôleur ci - dessous .On vaindex.htmlMettez - le surStaticSous le dossier, Et emballer les fichiers du projet comme DockerMiroir,DockerfileComme suit:
FROM golang:1.17 as builder
WORKDIR /
COPY . .
COPY static
RUN CGO_ENABLED=0 GOOS=linux go build -v -o main
FROM alpine
RUN apk add --no-cache ca-certificates
COPY --from=builder /main /usr/local/main
COPY --from=builder static /static
CMD ["/usr/local/main"]
Initialisation du projet
UtiliserKubebuilder Initialisation du projet miroir de commande
mkdir demo
cd demo
go mod init welcome_demo.domain
kubebuilder init --domain demo.welcome.domain
Après initialisation du projet,kubebuilder L'interface du projet de construction est la suivante:
[[email protected] demo]# tree .
.
├── config
│ ├── default
│ │ ├── kustomization.yaml
│ │ ├── manager_auth_proxy_patch.yaml
│ │ └── manager_config_patch.yaml
│ ├── manager
│ │ ├── controller_manager_config.yaml
│ │ ├── kustomization.yaml
│ │ └── manager.yaml
│ ├── prometheus
│ │ ├── kustomization.yaml
│ │ └── monitor.yaml
│ └── rbac
│ ├── auth_proxy_client_clusterrole.yaml
│ ├── auth_proxy_role_binding.yaml
│ ├── auth_proxy_role.yaml
│ ├── auth_proxy_service.yaml
│ ├── kustomization.yaml
│ ├── leader_election_role_binding.yaml
│ ├── leader_election_role.yaml
│ ├── role_binding.yaml
│ └── service_account.yaml
├── Dockerfile
├── go.mod
├── go.sum
├── hack
│ └── boilerplate.go.txt
├── main.go
├── Makefile
├── PROJECT
└── README.md
6 directories, 25 files
Création`Welcome` Kind Contrôleur correspondant
[[email protected] demo]# kubebuilder create api --group webapp --kind Welcome --version v1
Create Resource [y/n]
y
Create Controller [y/n]
y
Deux entréesy, Kubebuilder Les modèles de ressources et de contrôleurs sont créés séparément ,Icigroup、version、kindVoilà.3 Attributs combinés pour identifier un k8sDeCRD,Une fois la création terminée,KubebuilderAjouter le fichier suivant:
[[email protected] demo]# tree .
.
├── api
│ └── v1
│ ├── groupversion_info.go
│ ├── welcome_types.go
│ └── zz_generated.deepcopy.go
├── bin
│ └── controller-gen
├── config
│ ├── crd
│ │ ├── kustomization.yaml
│ │ ├── kustomizeconfig.yaml
│ │ └── patches
│ │ ├── cainjection_in_welcomes.yaml
│ │ └── webhook_in_welcomes.yaml
│ ├── default
│ │ ├── kustomization.yaml
│ │ ├── manager_auth_proxy_patch.yaml
│ │ └── manager_config_patch.yaml
│ ├── manager
│ │ ├── controller_manager_config.yaml
│ │ ├── kustomization.yaml
│ │ └── manager.yaml
│ ├── prometheus
│ │ ├── kustomization.yaml
│ │ └── monitor.yaml
│ ├── rbac
│ │ ├── auth_proxy_client_clusterrole.yaml
│ │ ├── auth_proxy_role_binding.yaml
│ │ ├── auth_proxy_role.yaml
│ │ ├── auth_proxy_service.yaml
│ │ ├── kustomization.yaml
│ │ ├── leader_election_role_binding.yaml
│ │ ├── leader_election_role.yaml
│ │ ├── role_binding.yaml
│ │ ├── service_account.yaml
│ │ ├── welcome_editor_role.yaml
│ │ └── welcome_viewer_role.yaml
│ └── samples
│ └── webapp_v1_welcome.yaml
├── controllers
│ ├── suite_test.go
│ └── welcome_controller.go
├── Dockerfile
├── go.mod
├── go.sum
├── hack
│ └── boilerplate.go.txt
├── main.go
├── Makefile
├── PROJECT
└── README.md
13 directories, 38 files
Deux étapes sont nécessaires par la suite :
- ModifierResource Type
- ModifierController Logique
ModifierResource Type
Ici.Resource Type Pour les champs de ressources à définir ,Utilisé dansYamlDéclaration dans le fichier, Ajouter dans ce cas name Champs pour “Welcome”KindDansWebApplication,Les codes sont les suivants::
vim api/v1/welcome_types.go
// WelcomeSpec defines the desired state of Welcome
type WelcomeSpec struct {
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
// Important: Run "make" to regenerate code after modifying this file
// Foo is an example field of Welcome. Edit welcome_types.go to remove/update
// Foo string `json:"foo,omitempty"`
Name string `json:"name,omitempty"`
}
ModifierControllerLogique
InControllerBesoin de passerReconcileMéthode terminéeDeploymentEtServiceDéploiement, Et finalement atteindre l'état souhaité .
vim controllers/welcome_controller.go
//+kubebuilder:rbac:groups=webapp.demo.welcome.domain,resources=welcomes,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=webapp.demo.welcome.domain,resources=welcomes/status,verbs=get;update;patch
//+kubebuilder:rbac:groups=webapp.demo.welcome.domain,resources=welcomes/finalizers,verbs=update
// Reconcile is part of the main kubernetes reconciliation loop which aims to
// move the current state of the cluster closer to the desired state.
// TODO(user): Modify the Reconcile function to compare the state specified by
// the Welcome object against the actual cluster state, and then
// perform operations to make the cluster state reflect the state specified by
// the user.
//
// For more details, check Reconcile and its Result here:
// - https://pkg.go.dev/sigs.k8s.io/[email protected]/pkg/reconcile
func (r *WelcomeReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
// _ = log.FromContext(ctx)
// TODO(user): your logic here
log := r.Log.WithValues("welcome", req.NamespacedName)
log.Info("reconcilling welcome")
return ctrl.Result{}, nil
}
- Le Code final est le suivant
/*
Copyright 2022.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controllers
import (
"context"
"fmt"
appsv1 "k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"sigs.k8s.io/controller-runtime/pkg/log"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
webappv1 "welcome_demo.domain/api/v1"
)
// WelcomeReconciler reconciles a Welcome object
type WelcomeReconciler struct {
client.Client
Scheme *runtime.Scheme
}
//+kubebuilder:rbac:groups=webapp.demo.welcome.domain,resources=welcomes,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=webapp.demo.welcome.domain,resources=welcomes/status,verbs=get;update;patch
//+kubebuilder:rbac:groups=webapp.demo.welcome.domain,resources=welcomes/finalizers,verbs=update
// Reconcile is part of the main kubernetes reconciliation loop which aims to
// move the current state of the cluster closer to the desired state.
// TODO(user): Modify the Reconcile function to compare the state specified by
// the Welcome object against the actual cluster state, and then
// perform operations to make the cluster state reflect the state specified by
// the user.
//
// For more details, check Reconcile and its Result here:
// - https://pkg.go.dev/sigs.k8s.io/[email protected]/pkg/reconcile
func (r *WelcomeReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
_ = log.FromContext(ctx)
// TODO(user): your logic here
welcome := &webappv1.Welcome{}
if err := r.Client.Get(ctx, req.NamespacedName, welcome); err != nil {
return ctrl.Result{}, err
}
deployment, err := r.createWelcomeDeployment(welcome)
if err != nil {
return ctrl.Result{}, err
}
fmt.Println("create deployment success!")
svc, err := r.createService(welcome)
if err != nil {
return ctrl.Result{}, err
}
fmt.Println("create service success!")
applyOpts := []client.PatchOption{client.ForceOwnership, client.FieldOwner("welcome_controller")}
err = r.Patch(ctx, &deployment, client.Apply, applyOpts...)
if err != nil {
return ctrl.Result{}, err
}
err = r.Patch(ctx, &svc, client.Apply, applyOpts...)
if err != nil {
return ctrl.Result{}, err
}
return ctrl.Result{}, nil
}
func (r *WelcomeReconciler) createWelcomeDeployment(welcome *webappv1.Welcome) (appsv1.Deployment, error) {
defOne := int32(1)
name := welcome.Spec.Name
if name == "" {
name = "world"
}
depl := appsv1.Deployment{
TypeMeta: metav1.TypeMeta{
APIVersion: appsv1.SchemeGroupVersion.String(),
Kind: "Deployment",
},
ObjectMeta: metav1.ObjectMeta{
Name: welcome.Name,
Namespace: welcome.Namespace,
},
Spec: appsv1.DeploymentSpec{
Replicas: &defOne,
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{"welcome": welcome.Name},
},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"welcome": welcome.Name},
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "welcome",
Env: []corev1.EnvVar{
{Name: "NAME", Value: name},
},
Ports: []corev1.ContainerPort{
{ContainerPort: 8080,
Name: "http",
Protocol: "TCP",
},
},
Image: "sdfcdwefe/operatordemo:v1",
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceCPU: *resource.NewMilliQuantity(100, resource.DecimalSI),
corev1.ResourceMemory: *resource.NewMilliQuantity(100000, resource.BinarySI),
},
},
},
},
},
},
},
}
return depl, nil
}
func (r *WelcomeReconciler) createService(welcome *webappv1.Welcome) (corev1.Service, error) {
svc := corev1.Service{
TypeMeta: metav1.TypeMeta{
APIVersion: corev1.SchemeGroupVersion.String(),
Kind: "Service"},
ObjectMeta: metav1.ObjectMeta{
Name: welcome.Name,
Namespace: welcome.Namespace,
},
Spec: corev1.ServiceSpec{
Ports: []corev1.ServicePort{
{Name: "http",
Port: 8080,
Protocol: "TCP",
TargetPort: intstr.FromString("http")},
},
Selector: map[string]string{"welcome": welcome.Name},
Type: corev1.ServiceTypeLoadBalancer,
},
}
return svc, nil
}
// SetupWithManager sets up the controller with the Manager.
func (r *WelcomeReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&webappv1.Welcome{}).
Complete(r)
}
(5)Welcome À déployer
- GénérerCRDRessources
[[email protected] demo]# make manifests
/root/demo/bin/controller-gen rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases
[[email protected] demo]# tree .
.
├── api
│ └── v1
│ ├── groupversion_info.go
│ ├── welcome_types.go
│ └── zz_generated.deepcopy.go
├── bin
│ └── controller-gen
├── config
│ ├── crd
│ │ ├── bases
│ │ │ └── webapp.demo.welcome.domain_welcomes.yaml
│ │ ├── kustomization.yaml
│ │ ├── kustomizeconfig.yaml
│ │ └── patches
│ │ ├── cainjection_in_welcomes.yaml
│ │ └── webhook_in_welcomes.yaml
│ ├── default
│ │ ├── kustomization.yaml
│ │ ├── manager_auth_proxy_patch.yaml
│ │ └── manager_config_patch.yaml
│ ├── manager
│ │ ├── controller_manager_config.yaml
│ │ ├── kustomization.yaml
│ │ └── manager.yaml
│ ├── prometheus
│ │ ├── kustomization.yaml
│ │ └── monitor.yaml
│ ├── rbac
│ │ ├── auth_proxy_client_clusterrole.yaml
│ │ ├── auth_proxy_role_binding.yaml
│ │ ├── auth_proxy_role.yaml
│ │ ├── auth_proxy_service.yaml
│ │ ├── kustomization.yaml
│ │ ├── leader_election_role_binding.yaml
│ │ ├── leader_election_role.yaml
│ │ ├── role_binding.yaml
│ │ ├── role.yaml
│ │ ├── service_account.yaml
│ │ ├── welcome_editor_role.yaml
│ │ └── welcome_viewer_role.yaml
│ └── samples
│ └── webapp_v1_welcome.yaml
├── controllers
│ ├── suite_test.go
│ └── welcome_controller.go
├── Dockerfile
├── go.mod
├── go.sum
├── hack
│ └── boilerplate.go.txt
├── main.go
├── Makefile
├── PROJECT
└── README.md
14 directories, 40 files
[[email protected] demo]# cat config/crd/bases/webapp.demo.welcome.domain_welcomes.yaml
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.9.0
creationTimestamp: null
name: welcomes.webapp.demo.welcome.domain
spec:
group: webapp.demo.welcome.domain
names:
kind: Welcome
listKind: WelcomeList
plural: welcomes
singular: welcome
scope: Namespaced
versions:
- name: v1
schema:
openAPIV3Schema:
description: Welcome is the Schema for the welcomes API
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
description: WelcomeSpec defines the desired state of Welcome
properties:
name:
description: Foo is an example field of Welcome. Edit welcome_types.go
to remove/update Foo string `json:"foo,omitempty"`
type: string
type: object
status:
description: WelcomeStatus defines the observed state of Welcome
type: object
type: object
served: true
storage: true
subresources:
status: {}
- CréationWelcomeType de ressource
[[email protected] demo]# kubectl create -f config/crd/bases/
customresourcedefinition.apiextensions.k8s.io/welcomes.webapp.demo.welcome.domain created
[[email protected] demo]# kubectl create -f config/samples/webapp_v1_welcome.yaml
welcome.webapp.demo.welcome.domain/welcome-sample created
- Utiliser`kubectl get crd` Commandes pour voir les objets personnalisés
[[email protected] demo]# kubectl get crd | grep welcome
welcomes.webapp.demo.welcome.domain 2022-06-25T09:10:37Z
- Adoptionkubectl get welcome La commande peut voir la création de welcomeObjet
[[email protected] demo]# kubectl get welcome
NAME AGE
welcome-sample 2m20s
En ce momentCRD Il n'y a pas de travail à faire ,C'est juste queETCD Un enregistrement a été créé dans ,On doit courirController Pour nous aider à faire notre travail et finalement atteindre welcomeStatut défini.
[[email protected] demo]# make run
/root/demo/bin/controller-gen rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases
/root/demo/bin/controller-gen object:headerFile="hack/boilerplate.go.txt" paths="./..."
go fmt ./...
api/v1/welcome_types.go
go vet ./...
go run ./main.go
1.6561485987622015e+09 INFO controller-runtime.metrics Metrics server is starting to listen {"addr": ":8080"}
1.6561485987624757e+09 INFO setup starting manager
1.6561485987638762e+09 INFO Starting server {"path": "/metrics", "kind": "metrics", "addr": "[::]:8080"}
1.656148598763948e+09 INFO Starting server {"kind": "health probe", "addr": "[::]:8081"}
1.656148598764167e+09 INFO Starting EventSource {"controller": "welcome", "controllerGroup": "webapp.demo.welcome.domain", "controllerKind": "Welcome", "source": "kind source: *v1.Welcome"}
1.6561485987641926e+09 INFO Starting Controller {"controller": "welcome", "controllerGroup": "webapp.demo.welcome.domain", "controllerKind": "Welcome"}
1.6561485988653958e+09 INFO Starting workers {"controller": "welcome", "controllerGroup": "webapp.demo.welcome.domain", "controllerKind": "Welcome", "worker count": 1}
create deployment success!
create service success!
La méthode ci - dessus démarre le Contrôleur localement , Facilité de mise en service et de vérification
- Voir la création dedeployment、service
[[email protected] demo]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
welcome-sample 1/1 1 1 34s
[[email protected] demo]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 4d2h
welcome-sample LoadBalancer 10.106.36.129 <pending> 8080:30037/TCP 39s
OperatorAutres articles connexes présentés par
- JavaScriptÉtendre l'opérateur(Spread operator)Introduction
Cet article présenteJavaScript Opérateur de déploiement pour (Spread operator)....Cet article convientES6Débutant. Vous pouvez agrandir l'opérateur (Spread operator)... Étendre un objet Array et une chaîne . Opération d'expansion ...
- Hyperledger Fabric 1.2 --- Chaincode Operator Interprétation et tests (Un.)
Préface Le but principal de cet article est d'organiser Hyperledger FabricÀ propos dechaincode Contenu de la gestion et des opérations ,Auteurrelease-1.2 Expliquer le modèle . Lien de référence principal: https://hyperl ...
- JavaScriptOpérateurs restantsRest Operator
Cet article convientJavaScript Lecture pour débutants Opérateurs restants L'article précédent JavaScriptÉtendre l'opérateur(Spread operator) Introduction à l'opérateur de déploiement . Les opérateurs restants sont représentés de la même manière que les opérateurs de déploiement , Trois points. ...
- prometheus operator(Kubernetes Surveillance des grappes)
Un..Prometheus Operator Introduction Prometheus Operator - Oui. CoreOS Base de développement Prometheus De Kubernetes Programme de surveillance, Ou peut - être la fonctionnalité la plus complète ...
- kubernets controller Et CRDExtension de
sample git repo Lignes directrices pour le développement de chaque composante operator Introduction Cette image est tirée de l'introduction pratique des employés de Google client-goUtilisation et analyse des sources (dlv) p pods *k8s.io/api/core/v ...
- C++ Opérateur surchargé pour (operator)Introduction(Tourne.)
Cet article présente principalementC++ Opérateur surchargé en (operator)Connaissances pertinentes. 1. Généralités 1.1 what operator - Oui.C++Un mot clé pour, Et les opérateurs (Par exemple:=)À utiliser ensemble, Représente une fonction de surcharge d'opérateur , Peut comprendre ...
- 【Python】operator Brève introduction au module
Une brève introduction à quelques fonctions communes , Voir la documentation pour plus de détails . operator.concat(a, b) **operator.__concat__(a, b)** Pour a.bSéquence,Retour a + b(Fusion de listes) -- ...
- PythonModule:operatorBrève introduction
PythonAdresse officielle du document:https://docs.python.org/3.6/library/operator.html?highlight=operator Operator Les fonctions fournies peuvent être utilisées pour comparer les objets ...
- C++ Opérateur surchargé pour (operator)Introduction
Le texte original est reproduit à:https://blog.csdn.net/liitdar/article/details/80654324 https://blog.csdn.net/liitdar/article/d ...
- Baptiser l'âme,Culturepython(14)--Moduledecimal, fractions,operator,collections Et introduction à la précision
decimal 1.Action: Pour le calcul du nombre de points flottants . .Par rapport à l'implémentation intégrée du nombre binaire de points flottants float Ce type aide Applications financières et autres situations nécessitant une représentation décimale précise ,Précision du contrôle, Contrôle de l'arrondissement pour tenir compte des exigences légales ou réglementaires , Assurer la précision des chiffres décimaux , ...
Recommandation aléatoire
- RésolutionmotoolsEtjqueryConflit entre
Une utilisation simultanée est nécessaire sur la même page motoolsEtjquery,Pour$,Il y a eu un conflit, Voici la solution . <head> <script src="./Scripts/lib/jquer ...
- python Django Chapitre avancé
PythonDeWEBLe cadre aDjango.Tornado.Flask Et bien plus encore.,DjangoPar rapport aux autresWEBLes avantages du cadre sont:Grand et complet,Le cadre lui - même est intégréORM.Reliure du modèle.Moteur de modèle.Cache.SessionEt bien plus encore. ...
- ServletDe5 Mise en œuvre de la soumission de formulaires de plusieurs façons ( Enregistrer les gadgets ), Obtenir les données du formulaire en arrière - plan
Avecservlet Réaliser une petite fonctionnalité enregistrée ,Obtenir des données en arrière - plan. Page d'inscription: Code de la page d'inscription : <!DOCTYPE html> <html> <head> <meta ...
- GIT Poster
1.Site officiel git-scm.com github.com Code Library 2.Code source
- oracle Générer un nombre aléatoire【À trier】
http://www.cnblogs.com/ulex/p/4415478.html http://blog.sina.com.cn/s/blog_6a01140c0100wimi.html
- linux ubuntuDésinstaller le logiciel
1.Adoptiondeb Conditions d'installation des paquets : Installation.debSac: Code:sudo dpkg -i package_file.debInstallation inversée.debSac: Code:sudo dpkg -r package_name 2.Adoptiona ...
- U31 Configuration de la gestion du réseau
1. Nouvelle configuration de l'élément réseau et de l'étagère Enfant : Créer un nouvel objet dans l'espace vide de la carte topologique - Créer un élément réseau de transport hébergé -Sélectionner le périphérique- Remplir le nom de l'élément réseau (A).Type d'élément réseau.IP(RechercheSNPDe),PasserelleIP Ajoutera automatiquement 2. Si la base de données est vide, sélectionnez d'abord hors ligne - Configuration du sous - rack ...
- POJ 2359 Questions(Joseph ring——Solution mathématique)
Liens vers les sujets: http://poj.org/problem?id=2359 Description du titre: Saisissez une chaîne Suivez les règles suivantes: , Si le dernier caractère restant est '?',Produits"Yes", Si le reste ...
- SQL CE Et SQLite Test de comparaison de la base de données
Besoins du projet , Le client a besoin d'une fonction de stockage de données , Choisi en tenant compte de la facilité de déploiement tout en répondant aux besoins fonctionnels SQLCE EtSQLite Deux bases de données pour le stockage de données client . Bien sûr, il y a beaucoup d'autres façons de stocker des données locales , Comme le stockage local de fichiers .Microsoft ...
- sshPratiques exemplaires en matière de services
Au travailsshMeilleures pratiques: N'utilisez pas le port par défaut Utilisation interditeprotocol version 1 (Par défautcentos6/7 L'utilisation de la première édition a été interdite ,Maiscentos5 Et peut - être que la première version est encore en service ) Restreindre les utilisateurs connectés SET NULL ...