istio

Форк
0
/
proxy.go 
230 строк · 6.8 Кб
1
// Copyright Istio Authors
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15
package envoy
16

17
import (
18
	"fmt"
19
	"os"
20
	"os/exec"
21
	"strings"
22
	"syscall"
23

24
	"google.golang.org/protobuf/types/known/durationpb"
25
	"sigs.k8s.io/yaml"
26

27
	"istio.io/istio/pilot/pkg/util/network"
28
	"istio.io/istio/pkg/env"
29
	common_features "istio.io/istio/pkg/features"
30
	"istio.io/istio/pkg/log"
31
)
32

33
type envoy struct {
34
	ProxyConfig
35
	extraArgs []string
36
}
37

38
// Envoy binary flags
39
type ProxyConfig struct {
40
	LogLevel          string
41
	ComponentLogLevel string
42
	NodeIPs           []string
43
	Sidecar           bool
44
	LogAsJSON         bool
45
	// TODO: outlier log path configuration belongs to mesh ProxyConfig
46
	OutlierLogPath string
47

48
	BinaryPath    string
49
	ConfigPath    string
50
	ConfigCleanup bool
51
	AdminPort     int32
52
	DrainDuration *durationpb.Duration
53
	Concurrency   int32
54

55
	// For unit testing, in combination with NoEnvoy prevents agent.Run from blocking
56
	TestOnly    bool
57
	AgentIsRoot bool
58

59
	// Is the proxy in Dual Stack environment
60
	DualStack bool
61
}
62

63
// NewProxy creates an instance of the proxy control commands
64
func NewProxy(cfg ProxyConfig) Proxy {
65
	// inject tracing flag for higher levels
66
	var args []string
67
	logLevel, componentLogs := splitComponentLog(cfg.LogLevel)
68
	if logLevel != "" {
69
		args = append(args, "-l", logLevel)
70
	}
71
	if len(componentLogs) > 0 {
72
		args = append(args, "--component-log-level", strings.Join(componentLogs, ","))
73
	} else if cfg.ComponentLogLevel != "" {
74
		// Use the old setting if we don't set any component log levels in LogLevel
75
		args = append(args, "--component-log-level", cfg.ComponentLogLevel)
76
	}
77

78
	// Explicitly enable core dumps. This may be desirable more often (by default), but for now we only set it in VM tests.
79
	if enableEnvoyCoreDump {
80
		args = append(args, "--enable-core-dump")
81
	}
82
	return &envoy{
83
		ProxyConfig: cfg,
84
		extraArgs:   args,
85
	}
86
}
87

88
// splitComponentLog breaks down an argument string into a log level (ie "info") and component log levels (ie "misc:error").
89
// This allows using a single log level API, with the same semantics as Istio's logging, to configure Envoy which
90
// has two different settings
91
func splitComponentLog(level string) (string, []string) {
92
	levels := strings.Split(level, ",")
93
	var logLevel string
94
	var componentLogs []string
95
	for _, sl := range levels {
96
		spl := strings.Split(sl, ":")
97
		if len(spl) == 1 {
98
			logLevel = spl[0]
99
		} else if len(spl) == 2 {
100
			componentLogs = append(componentLogs, sl)
101
		} else {
102
			log.Warnf("dropping invalid log level: %v", sl)
103
		}
104
	}
105
	return logLevel, componentLogs
106
}
107

108
func (e *envoy) Drain(skipExit bool) error {
109
	adminPort := uint32(e.AdminPort)
110

111
	err := DrainListeners(adminPort, e.Sidecar, skipExit)
112
	if err != nil {
113
		log.Infof("failed draining listeners for Envoy on port %d: %v", adminPort, err)
114
	}
115
	return err
116
}
117

118
func (e *envoy) UpdateConfig(config []byte) error {
119
	return os.WriteFile(e.ConfigPath, config, 0o666)
120
}
121

122
func (e *envoy) args(fname string, overrideFname string) []string {
123
	proxyLocalAddressType := "v4"
124
	if network.AllIPv6(e.NodeIPs) {
125
		proxyLocalAddressType = "v6"
126
	}
127
	startupArgs := []string{
128
		"-c", fname,
129
		"--drain-time-s", fmt.Sprint(int(e.DrainDuration.AsDuration().Seconds())),
130
		"--drain-strategy", "immediate", // Clients are notified as soon as the drain process starts.
131
		"--local-address-ip-version", proxyLocalAddressType,
132
		// Reduce default flush interval from 10s to 1s. The access log buffer size is 64k and each log is ~256 bytes
133
		// This means access logs will be written once we have ~250 requests, or ever 1s, which ever comes first.
134
		// Reducing this to 1s optimizes for UX while retaining performance.
135
		// At low QPS access logs are unlikely a bottleneck, and these users will now see logs after 1s rather than 10s.
136
		// At high QPS (>250 QPS) we will log the same amount as we will log due to exceeding buffer size, rather
137
		// than the flush interval.
138
		"--file-flush-interval-msec", "1000",
139
		"--disable-hot-restart", // We don't use it, so disable it to simplify Envoy's logic
140
		"--allow-unknown-static-fields",
141
	}
142

143
	startupArgs = append(startupArgs, e.extraArgs...)
144

145
	if overrideFname != "" {
146
		s, err := readToJSON(overrideFname)
147
		if err != nil {
148
			log.Warnf("Failed to read bootstrap override: %v", err)
149
		} else {
150
			// Despite the name Envoy also accepts JSON string
151
			startupArgs = append(startupArgs, "--config-yaml", s)
152
		}
153
	}
154

155
	if e.Concurrency > 0 {
156
		startupArgs = append(startupArgs, "--concurrency", fmt.Sprint(e.Concurrency))
157
	}
158

159
	return startupArgs
160
}
161

162
// readToJSON reads a config file, in YAML or JSON, and returns JSON string
163
func readToJSON(fname string) (string, error) {
164
	bytes, err := os.ReadFile(fname)
165
	if err != nil {
166
		return "", fmt.Errorf("failed to read file: %s, %v", fname, err)
167
	}
168

169
	converted, err := yaml.YAMLToJSON(bytes)
170
	if err != nil {
171
		return "", fmt.Errorf("failed to convert to JSON: %s, %v", fname, err)
172
	}
173
	return string(converted), nil
174
}
175

176
var (
177
	istioBootstrapOverrideVar = env.Register("ISTIO_BOOTSTRAP_OVERRIDE", "", "")
178
	enableEnvoyCoreDump       = env.Register("ISTIO_ENVOY_ENABLE_CORE_DUMP", false, "").Get()
179
)
180

181
func (e *envoy) Run(abort <-chan error) error {
182
	// spin up a new Envoy process
183
	args := e.args(e.ConfigPath, istioBootstrapOverrideVar.Get())
184
	log.Infof("Envoy command: %v", args)
185

186
	/* #nosec */
187
	cmd := exec.Command(e.BinaryPath, args...)
188
	cmd.Env = os.Environ()
189
	if common_features.CompliancePolicy == common_features.FIPS_140_2 {
190
		// Limit the TLSv1.2 ciphers in google_grpc client in Envoy to the compliant ciphers.
191
		cmd.Env = append(cmd.Env,
192
			"GRPC_SSL_CIPHER_SUITES=ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384")
193
	}
194
	cmd.Stdout = os.Stdout
195
	cmd.Stderr = os.Stderr
196
	if e.AgentIsRoot {
197
		cmd.SysProcAttr = &syscall.SysProcAttr{}
198
		cmd.SysProcAttr.Credential = &syscall.Credential{
199
			Uid: 1337,
200
			Gid: 1337,
201
		}
202
	}
203

204
	if err := cmd.Start(); err != nil {
205
		return err
206
	}
207
	done := make(chan error, 1)
208
	go func() {
209
		done <- cmd.Wait()
210
	}()
211

212
	select {
213
	case err := <-abort:
214
		log.Warnf("Aborting proxy")
215
		if errKill := cmd.Process.Kill(); errKill != nil {
216
			log.Warnf("killing proxy caused an error %v", errKill)
217
		}
218
		return err
219
	case err := <-done:
220
		return err
221
	}
222
}
223

224
func (e *envoy) Cleanup() {
225
	if e.ConfigCleanup {
226
		if err := os.Remove(e.ConfigPath); err != nil {
227
			log.Warnf("Failed to delete config file %s: %v", e.ConfigPath, err)
228
		}
229
	}
230
}
231

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.