欢迎关注我的公众号:
目前刚开始写一个月,一共写了18篇原创文章,文章目录如下:
istio防故障利器,你知道几个,istio新手不要读,太难!
不懂envoyfilter也敢说精通istio系列-http-rbac-不要只会用AuthorizationPolicy配置权限
不懂envoyfilter也敢说精通istio系列-02-http-corsFilter-不要只会vs
不懂envoyfilter也敢说精通istio系列-03-http-csrf filter-再也不用再代码里写csrf逻辑了
不懂envoyfilter也敢说精通istio系列http-jwt_authn-不要只会RequestAuthorization
不懂envoyfilter也敢说精通istio系列-05-fault-filter-故障注入不止是vs
不懂envoyfilter也敢说精通istio系列-06-http-match-配置路由不只是vs
不懂envoyfilter也敢说精通istio系列-07-负载均衡配置不止是dr
不懂envoyfilter也敢说精通istio系列-08-连接池和断路器
不懂envoyfilter也敢说精通istio系列-09-http-route filter
不懂envoyfilter也敢说精通istio系列-network filter-redis proxy
不懂envoyfilter也敢说精通istio系列-network filter-HttpConnectionManager
不懂envoyfilter也敢说精通istio系列-ratelimit-istio ratelimit完全手册
加qq群,请联系:
————————————————
type EnvOptions struct {//set env结构体
PrintFlags *genericclioptions.PrintFlags
resource.FilenameOptions
EnvParams []string
All bool
Resolve bool
List bool
Local bool
Overwrite bool
ContainerSelector string
Selector string
From string
Prefix string
Keys []string
PrintObj printers.ResourcePrinterFunc
envArgs []string
resources []string
output string
dryRun bool
builder func() *resource.Builder
updatePodSpecForObject polymorphichelpers.UpdatePodSpecForObjectFunc
namespace string
enforceNamespace bool
clientset *kubernetes.Clientset
genericclioptions.IOStreams
}
func NewEnvOptions(streams genericclioptions.IOStreams) *EnvOptions {
return &EnvOptions{//初始化结构体
PrintFlags: genericclioptions.NewPrintFlags("env updated").WithTypeSetter(scheme.Scheme),
ContainerSelector: "*",
Overwrite: true,
IOStreams: streams,
}
}
//创建set env命令
func NewCmdEnv(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
o := NewEnvOptions(streams)//初始化结构体
cmd := &cobra.Command{//创建cobra命令
Use: "env RESOURCE/NAME KEY_1=VAL_1 ... KEY_N=VAL_N",
DisableFlagsInUseLine: true,
Short: "Update environment variables on a pod template",
Long: envLong,
Example: fmt.Sprintf(envExample),
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))//准备
cmdutil.CheckErr(o.Validate())//校验
cmdutil.CheckErr(o.RunEnv())//运行
},
}
usage := "the resource to update the env"
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage)//设置文件选项
cmd.Flags().StringVarP(&o.ContainerSelector, "containers", "c", o.ContainerSelector, "The names of containers in the selected pod templates to change - may use wildcards")//设置container选项
cmd.Flags().StringVarP(&o.From, "from", "", "", "The name of a resource from which to inject environment variables")//设置from选项
cmd.Flags().StringVarP(&o.Prefix, "prefix", "", "", "Prefix to append to variable names")//设置prefix选项
cmd.Flags().StringArrayVarP(&o.EnvParams, "env", "e", o.EnvParams, "Specify a key-value pair for an environment variable to set into each container.")//设置env选项
cmd.Flags().StringSliceVarP(&o.Keys, "keys", "", o.Keys, "Comma-separated list of keys to import from specified resource")//设置keys选项
cmd.Flags().BoolVar(&o.List, "list", o.List, "If true, display the environment and any changes in the standard format. this flag will removed when we have kubectl view env.")//设置list选项
cmd.Flags().BoolVar(&o.Resolve, "resolve", o.Resolve, "If true, show secret or configmap references when listing variables")//设置resolve选项
cmd.Flags().StringVarP(&o.Selector, "selector", "l", o.Selector, "Selector (label query) to filter on")//设置selector选项
cmd.Flags().BoolVar(&o.Local, "local", o.Local, "If true, set env will NOT contact api-server but run locally.")//设置local选项
cmd.Flags().BoolVar(&o.All, "all", o.All, "If true, select all resources in the namespace of the specified resource types")//设置all选项
cmd.Flags().BoolVar(&o.Overwrite, "overwrite", o.Overwrite, "If true, allow environment to be overwritten, otherwise reject updates that overwrite existing environment.")//设置overrite选项
o.PrintFlags.AddFlags(cmd)//设置打印选项
cmdutil.AddDryRunFlag(cmd)//设置干跑选项
return cmd
}
//准备
func (o *EnvOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
if o.All && len(o.Selector) > 0 {//all和selector不能同时存在
return fmt.Errorf("cannot set --all and --selector at the same time")
}
ok := false
o.resources, o.envArgs, ok = envutil.SplitEnvironmentFromResources(args)//获取resource和env
if !ok {
return fmt.Errorf("all resources must be specified before environment changes: %s", strings.Join(args, " "))
}
o.updatePodSpecForObject = polymorphichelpers.UpdatePodSpecForObjectFn//设置updatePodSpecForObject函数
o.output = cmdutil.GetFlagString(cmd, "output")//设置output
o.dryRun = cmdutil.GetDryRunFlag(cmd)//设置干跑
if o.dryRun {
// TODO(juanvallejo): This can be cleaned up even further by creating
// a PrintFlags struct that binds the --dry-run flag, and whose
// ToPrinter method returns a printer that understands how to print
// this success message.
o.PrintFlags.Complete("%s (dry run)")
}
printer, err := o.PrintFlags.ToPrinter()//printflag转printer
if err != nil {
return err
}
o.PrintObj = printer.PrintObj//设置printObj函数
o.clientset, err = f.KubernetesClientSet()//设置clientSet
if err != nil {
return err
}
o.namespace, o.enforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()//设置namespace和enforceNamespace
if err != nil {
return err
}
o.builder = f.NewBuilder//设置builder
return nil
}
func (o *EnvOptions) Validate() error {
if len(o.Filenames) == 0 && len(o.resources) < 1 {//文件和资源至少有一个
return fmt.Errorf("one or more resources must be specified as <resource> <name> or <resource>/<name>")
}
if o.List && len(o.output) > 0 {//list和output不能同时指定
return fmt.Errorf("--list and --output may not be specified together")
}
if len(o.Keys) > 0 && len(o.From) == 0 {指定keys的时候必须指定from
return fmt.Errorf("when specifying --keys, a configmap or secret must be provided with --from")
}
return nil
}
//运行
func (o *EnvOptions) RunEnv() error {
env, remove, err := envutil.ParseEnv(append(o.EnvParams, o.envArgs...), o.In)//解析env
if err != nil {
return err
}
if len(o.From) != 0 {
b := o.builder().
WithScheme(scheme.Scheme, scheme.Scheme.PrioritizedVersionsAllGroups()...).
LocalParam(o.Local).
ContinueOnError().
NamespaceParam(o.namespace).DefaultNamespace().
FilenameParam(o.enforceNamespace, &o.FilenameOptions).
Flatten()//构造from的info对象
if !o.Local {
b = b.
LabelSelectorParam(o.Selector).
ResourceTypeOrNameArgs(o.All, o.From).
Latest()
}
infos, err := b.Do().Infos()//获取from info对象
if err != nil {
return err
}
for _, info := range infos {//遍历from info对象
switch from := info.Object.(type) {
case *v1.Secret://如果类型是secret
for key := range from.Data {//遍历key
if contains(key, o.Keys) {//如果keys包含key
envVar := v1.EnvVar{
Name: keyToEnvName(key),
ValueFrom: &v1.EnvVarSource{
SecretKeyRef: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: from.Name,
},
Key: key,
},
},
}//构造env
env = append(env, envVar)//append env
}
}
case *v1.ConfigMap://如果类型是configMap
for key := range from.Data {//遍历key
if contains(key, o.Keys) {//如果keys包含key
envVar := v1.EnvVar{
Name: keyToEnvName(key),
ValueFrom: &v1.EnvVarSource{
ConfigMapKeyRef: &v1.ConfigMapKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: from.Name,
},
Key: key,
},
},
}//构造env
env = append(env, envVar)//append env
}
}
default:
return fmt.Errorf("unsupported resource specified in --from")
}
}
}
if len(o.Prefix) != 0 {//如果prefix不为空
for i := range env {
env[i].Name = fmt.Sprintf("%s%s", o.Prefix, env[i].Name)//env名称加prefix
}
}
b := o.builder().
WithScheme(scheme.Scheme, scheme.Scheme.PrioritizedVersionsAllGroups()...).
LocalParam(o.Local).
ContinueOnError().
NamespaceParam(o.namespace).DefaultNamespace().
FilenameParam(o.enforceNamespace, &o.FilenameOptions).
Flatten()//构造resource 的info对象
if !o.Local {
b.LabelSelectorParam(o.Selector).
ResourceTypeOrNameArgs(o.All, o.resources...).
Latest()
}
infos, err := b.Do().Infos()//获取info对象
if err != nil {
return err
}
patches := CalculatePatches(infos, scheme.DefaultJSONEncoder(), func(obj runtime.Object) ([]byte, error) {//计算patch
_, err := o.updatePodSpecForObject(obj, func(spec *v1.PodSpec) error {//更新pod spec
resolutionErrorsEncountered := false
containers, _ := selectContainers(spec.Containers, o.ContainerSelector)//选择容器
objName, err := meta.NewAccessor().Name(obj)//获取对象名称
if err != nil {
return err
}
gvks, _, err := scheme.Scheme.ObjectKinds(obj)//从obj获取groupversionkind
if err != nil {
return err
}
objKind := obj.GetObjectKind().GroupVersionKind().Kind//获取kind
if len(objKind) == 0 {//如果kind为空,则从gvks获取
for _, gvk := range gvks {
if len(gvk.Kind) == 0 {
continue
}
if len(gvk.Version) == 0 || gvk.Version == runtime.APIVersionInternal {
continue
}
objKind = gvk.Kind
break
}
}
if len(containers) == 0 {//如果容器为空
if gvks, _, err := scheme.Scheme.ObjectKinds(obj); err == nil {//获取gvks
objKind := obj.GetObjectKind().GroupVersionKind().Kind//获取kind
if len(objKind) == 0 {//如果kind为空则从gvks获取
for _, gvk := range gvks {
if len(gvk.Kind) == 0 {
continue
}
if len(gvk.Version) == 0 || gvk.Version == runtime.APIVersionInternal {
continue
}
objKind = gvk.Kind
break
}
}
fmt.Fprintf(o.ErrOut, "warning: %s/%s does not have any containers matching %q\n", objKind, objName, o.ContainerSelector)//打印错误返回
}
return nil
}
for _, c := range containers {//遍历容器
if !o.Overwrite {//如果overrite为false,校验env是否有覆盖
if err := validateNoOverwrites(c.Env, env); err != nil {
return err
}
}
c.Env = updateEnv(c.Env, env, remove)//更新env
if o.List {//如果list为true
resolveErrors := map[string][]string{}
store := envutil.NewResourceStore()
fmt.Fprintf(o.Out, "# %s %s, container %s\n", objKind, objName, c.Name)
for _, env := range c.Env {//遍历env
// Print the simple value
if env.ValueFrom == nil {//打印env
fmt.Fprintf(o.Out, "%s=%s\n", env.Name, env.Value)
continue
}
// Print the reference version
if !o.Resolve {//如果resolve为false,不解析env,打印
fmt.Fprintf(o.Out, "# %s from %s\n", env.Name, envutil.GetEnvVarRefString(env.ValueFrom))
continue
}
value, err := envutil.GetEnvVarRefValue(o.clientset, o.namespace, store, env.ValueFrom, obj, c)//解析env
// Print the resolved value
if err == nil {//打印解析后的env
fmt.Fprintf(o.Out, "%s=%s\n", env.Name, value)
continue
}
// Print the reference version and save the resolve error
fmt.Fprintf(o.Out, "# %s from %s\n", env.Name, envutil.GetEnvVarRefString(env.ValueFrom))//解析错误,打印未解析env
errString := err.Error()
resolveErrors[errString] = append(resolveErrors[errString], env.Name)
resolutionErrorsEncountered = true
}
// Print any resolution errors
errs := []string{}
for err, vars := range resolveErrors {
sort.Strings(vars)
errs = append(errs, fmt.Sprintf("error retrieving reference for %s: %v", strings.Join(vars, ", "), err))//组装error
}
sort.Strings(errs)//排序error
for _, err := range errs {//打印错误
fmt.Fprintln(o.ErrOut, err)
}
}
}
if resolutionErrorsEncountered {//解析错误返回
return errors.New("failed to retrieve valueFrom references")
}
return nil
})
if err == nil {
return runtime.Encode(scheme.DefaultJSONEncoder(), obj)//obj转json
}
return nil, err
})
if o.List {
return nil
}
allErrs := []error{}
for _, patch := range patches {//遍历patch
info := patch.Info
if patch.Err != nil {
name := info.ObjectName()
allErrs = append(allErrs, fmt.Errorf("error: %s %v\n", name, patch.Err))
continue
}
// no changes
if string(patch.Patch) == "{}" || len(patch.Patch) == 0 {
continue
}
if o.Local || o.dryRun {//loal或干跑,打印结果继续
if err := o.PrintObj(info.Object, o.Out); err != nil {
allErrs = append(allErrs, err)
}
continue
}
actual, err := resource.NewHelper(info.Client, info.Mapping).Patch(info.Namespace, info.Name, types.StrategicMergePatchType, patch.Patch, nil)//应用patch到服务端
if err != nil {
allErrs = append(allErrs, fmt.Errorf("failed to patch env update to pod template: %v", err))
continue
}
// make sure arguments to set or replace environment variables are set
// before returning a successful message
if len(env) == 0 && len(o.envArgs) == 0 {//如果env和envArgs为空则报错
return fmt.Errorf("at least one environment variable must be provided")
}
if err := o.PrintObj(actual, o.Out); err != nil {//打印结果
allErrs = append(allErrs, err)
}
}
return utilerrors.NewAggregate(allErrs)
}