6.1 ConfigMap基础概念
1. ConfigMap概述
ConfigMap是Kubernetes中用于存储非敏感配置数据的API对象,它将配置数据与应用程序代码分离,提高了应用的可移植性和可维护性。
ConfigMap特性: - 存储键值对配置数据 - 支持多种数据格式(文本、JSON、YAML等) - 可以作为环境变量、命令行参数或配置文件使用 - 支持热更新(部分场景) - 非敏感数据存储
ConfigMap使用场景: - 应用程序配置文件 - 环境变量配置 - 命令行参数 - 静态网页内容 - 脚本文件
2. 创建ConfigMap的方式
方式1:使用kubectl命令行
create-configmap.sh
#!/bin/bash
echo "=== 创建ConfigMap示例 ==="
# 1. 从字面值创建
echo "1. 从字面值创建ConfigMap:"
kubectl create configmap app-config \
--from-literal=database.host=mysql.example.com \
--from-literal=database.port=3306 \
--from-literal=database.name=myapp \
--from-literal=log.level=info
# 2. 从文件创建
echo "\n2. 从文件创建ConfigMap:"
# 创建配置文件
cat > app.properties << EOF
database.host=mysql.example.com
database.port=3306
database.name=myapp
log.level=info
max.connections=100
EOF
kubectl create configmap app-properties --from-file=app.properties
# 3. 从目录创建
echo "\n3. 从目录创建ConfigMap:"
mkdir -p config
cat > config/database.conf << EOF
[database]
host = mysql.example.com
port = 3306
name = myapp
user = appuser
EOF
cat > config/logging.conf << EOF
[logging]
level = info
format = json
output = stdout
EOF
kubectl create configmap app-configs --from-file=config/
# 4. 从环境文件创建
echo "\n4. 从环境文件创建ConfigMap:"
cat > .env << EOF
DATABASE_HOST=mysql.example.com
DATABASE_PORT=3306
DATABASE_NAME=myapp
LOG_LEVEL=info
EOF
kubectl create configmap app-env --from-env-file=.env
# 查看创建的ConfigMap
echo "\n5. 查看创建的ConfigMap:"
kubectl get configmaps
kubectl describe configmap app-config
echo "\n=== ConfigMap创建完成 ==="
方式2:使用YAML文件
basic-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: default
labels:
app: myapp
env: production
data:
# 简单键值对
database.host: "mysql.example.com"
database.port: "3306"
database.name: "myapp"
log.level: "info"
# 配置文件内容
app.properties: |
database.host=mysql.example.com
database.port=3306
database.name=myapp
log.level=info
max.connections=100
timeout=30
# JSON配置
config.json: |
{
"database": {
"host": "mysql.example.com",
"port": 3306,
"name": "myapp"
},
"logging": {
"level": "info",
"format": "json"
}
}
# YAML配置
config.yaml: |
database:
host: mysql.example.com
port: 3306
name: myapp
logging:
level: info
format: json
features:
- authentication
- authorization
- monitoring
# 脚本文件
init.sh: |
#!/bin/bash
echo "Initializing application..."
echo "Database host: $DATABASE_HOST"
echo "Database port: $DATABASE_PORT"
echo "Starting application..."
# Nginx配置
nginx.conf: |
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://backend:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
location /static {
root /var/www;
expires 1d;
}
}
3. 在Pod中使用ConfigMap
方式1:作为环境变量
configmap-env.yaml
apiVersion: v1
kind: Pod
metadata:
name: app-with-configmap-env
spec:
containers:
- name: app
image: busybox:1.35
command: ['sh', '-c', 'env | grep -E "(DATABASE|LOG)" && sleep 3600']
env:
# 单个键值对
- name: DATABASE_HOST
valueFrom:
configMapKeyRef:
name: app-config
key: database.host
- name: DATABASE_PORT
valueFrom:
configMapKeyRef:
name: app-config
key: database.port
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: app-config
key: log.level
# 导入所有键值对
envFrom:
- configMapRef:
name: app-config
# 带前缀导入
- configMapRef:
name: app-config
prefix: APP_
restartPolicy: Never
---
# 使用Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-deployment
spec:
replicas: 2
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: app
image: nginx:1.20
env:
- name: DATABASE_HOST
valueFrom:
configMapKeyRef:
name: app-config
key: database.host
- name: DATABASE_PORT
valueFrom:
configMapKeyRef:
name: app-config
key: database.port
envFrom:
- configMapRef:
name: app-config
ports:
- containerPort: 80
方式2:作为卷挂载
configmap-volume.yaml
apiVersion: v1
kind: Pod
metadata:
name: app-with-configmap-volume
spec:
containers:
- name: app
image: nginx:1.20
volumeMounts:
# 挂载整个ConfigMap
- name: config-volume
mountPath: /etc/config
readOnly: true
# 挂载特定文件
- name: app-properties
mountPath: /etc/app/app.properties
subPath: app.properties
readOnly: true
# 挂载Nginx配置
- name: nginx-config
mountPath: /etc/nginx/conf.d/default.conf
subPath: nginx.conf
readOnly: true
# 挂载脚本文件
- name: init-script
mountPath: /usr/local/bin/init.sh
subPath: init.sh
readOnly: true
command: ['sh', '-c', 'ls -la /etc/config && cat /etc/app/app.properties && sleep 3600']
volumes:
# 挂载整个ConfigMap
- name: config-volume
configMap:
name: app-config
# 挂载特定键
- name: app-properties
configMap:
name: app-config
items:
- key: app.properties
path: app.properties
# 挂载Nginx配置
- name: nginx-config
configMap:
name: app-config
items:
- key: nginx.conf
path: nginx.conf
# 挂载脚本文件并设置权限
- name: init-script
configMap:
name: app-config
items:
- key: init.sh
path: init.sh
mode: 0755 # 设置执行权限
defaultMode: 0644
restartPolicy: Never
方式3:作为命令行参数
configmap-args.yaml
apiVersion: v1
kind: Pod
metadata:
name: app-with-configmap-args
spec:
containers:
- name: app
image: busybox:1.35
command: ['sh']
args:
- '-c'
- |
echo "Starting application with parameters:"
echo "Database Host: $1"
echo "Database Port: $2"
echo "Log Level: $3"
sleep 3600
- $(DATABASE_HOST)
- $(DATABASE_PORT)
- $(LOG_LEVEL)
env:
- name: DATABASE_HOST
valueFrom:
configMapKeyRef:
name: app-config
key: database.host
- name: DATABASE_PORT
valueFrom:
configMapKeyRef:
name: app-config
key: database.port
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: app-config
key: log.level
restartPolicy: Never
6.2 Secret基础概念
1. Secret概述
Secret是Kubernetes中用于存储敏感数据的API对象,如密码、OAuth令牌、SSH密钥等。Secret与ConfigMap类似,但专门用于敏感信息。
Secret特性: - 存储敏感数据(Base64编码) - 数据在etcd中加密存储 - 支持多种Secret类型 - 可以作为环境变量或文件挂载使用 - 访问权限控制
Secret类型: - Opaque - 用户自定义数据(默认) - kubernetes.io/service-account-token - ServiceAccount令牌 - kubernetes.io/dockercfg - Docker配置文件 - kubernetes.io/dockerconfigjson - Docker配置JSON - kubernetes.io/basic-auth - 基本认证 - kubernetes.io/ssh-auth - SSH认证 - kubernetes.io/tls - TLS证书
2. 创建Secret的方式
方式1:使用kubectl命令行
create-secret.sh
#!/bin/bash
echo "=== 创建Secret示例 ==="
# 1. 创建通用Secret
echo "1. 创建通用Secret:"
kubectl create secret generic app-secret \
--from-literal=database.username=admin \
--from-literal=database.password=secretpassword \
--from-literal=api.key=abc123xyz789
# 2. 创建Docker Registry Secret
echo "\n2. 创建Docker Registry Secret:"
kubectl create secret docker-registry docker-secret \
--docker-server=registry.example.com \
--docker-username=myuser \
--docker-password=mypassword \
--docker-email=user@example.com
# 3. 创建TLS Secret
echo "\n3. 创建TLS Secret:"
# 生成自签名证书(仅用于测试)
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout tls.key -out tls.crt \
-subj "/CN=example.com/O=example.com"
kubectl create secret tls tls-secret \
--cert=tls.crt \
--key=tls.key
# 4. 创建SSH Secret
echo "\n4. 创建SSH Secret:"
# 生成SSH密钥对(仅用于测试)
ssh-keygen -t rsa -b 2048 -f ssh-key -N ""
kubectl create secret generic ssh-secret \
--from-file=ssh-privatekey=ssh-key \
--from-file=ssh-publickey=ssh-key.pub
# 5. 从文件创建Secret
echo "\n5. 从文件创建Secret:"
cat > database.conf << EOF
host=mysql.example.com
port=3306
username=admin
password=secretpassword
EOF
kubectl create secret generic db-config-secret --from-file=database.conf
# 查看创建的Secret
echo "\n6. 查看创建的Secret:"
kubectl get secrets
kubectl describe secret app-secret
# 清理临时文件
rm -f tls.crt tls.key ssh-key ssh-key.pub database.conf
echo "\n=== Secret创建完成 ==="
方式2:使用YAML文件
basic-secret.yaml “`yaml
通用Secret
apiVersion: v1 kind: Secret metadata: name: app-secret namespace: default labels: app: myapp env: production type: Opaque data: # Base64编码的数据 database.username: YWRtaW4= # admin database.password: c2VjcmV0cGFzc3dvcmQ= # secretpassword api.key: YWJjMTIzeHl6Nzg5 # abc123xyz789
# 配置文件内容(Base64编码) database.conf: | aG9zdD1teXNxbC5leGFtcGxlLmNvbQpwb3J0PTMzMDYKdXNlcm5hbWU9YWRtaW4KcGFzc3dvcmQ9c2VjcmV0cGFzc3dvcmQK
Docker Registry Secret
apiVersion: v1 kind: Secret metadata: name: docker-registry-secret type: kubernetes.io/dockerconfigjson data: .dockerconfigjson: | eyJhdXRocyI6eyJyZWdpc3RyeS5leGFtcGxlLmNvbSI6eyJ1c2VybmFtZSI6Im15dXNlciIsInBhc3N3b3JkIjoibXlwYXNzd29yZCIsImVtYWlsIjoidXNlckBleGFtcGxlLmNvbSIsImF1dGgiOiJiWGwxYzJWeU9tMTVjR0Z6YzNkdmNtUT0ifX19
TLS Secret
apiVersion: v1 kind: Secret metadata: name: tls-secret type: kubernetes.io/tls data: tls.crt: | LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURMakNDQWhZQ0NRREFPRjl0THNhWFdqQU5CZ2txaGtpRzl3MEJBUXNGQURBU01SQXdEZ1lEVlFRRERBZHUKYjJSbGJHbHVhekFlRncweE9ERXlNakF4TkRVNU1qVmFGdzB4T1RFeU1qQXhORFU1TWpWYU1ESXhFREFPQmdOVgpCQU1NQjI1dlpHVnNhVzVyTVE0d0RBWURWUVFLREFWdWIyUmxiR2x1YXpFUE1BMEdBMVVFQnd3R1RtOWtaV3hwCmJtc3hEVEFMQmdOVkJBZ01CRTVQUkVVeEN6QUpCZ05WQkFZVEFrNVBNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUYKQUFPQ0FROEFNSUlCQ2dLQ0FRRUF0Y1o5UW9UQzJTVHFmNjQ4a1Q4eVJkOXdkdGVtS2p2UUlaWnJHSTlHVGpNNApGbXZOQ3lqSXdRSUNpMkNBL2pJQ2ZqbHVuOXdVV2VkMFVhYU9tUUNyVm5kK1Q3Y2psdHdoYkVoUzI1ZGtaNStjCmI5Q09VbHhGY1FxZWs1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTEKZkJXK3Bkc1FqVnZkK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXFlazVxYjgvZWpaQmUrZUFmSTdaQgpmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQlcrcGRzUWpWdmQrdDdjalJkOXdkdGVtS2p2UUlaClpyR0k5R1RqTTRGbXZOQ3lqSXdRSUNpMkNBL2pJQ2ZqbHVuOXdVV2VkMFVhYU9tUUNyVm5kK1Q3Y2psdHdoYkUKaFMyNWRrWjUrY2I5Q09VbHhGY1FxZWs1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLwo1Y1plQURmcGUxZkJXK3Bkc1FqVnZkK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXFlazVxYjgvZWpaClJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQlcrcGRzUWpWdmQrdDdjalJkOXcKZHRlbUtqdlFJWlpyR0k5R1RqTTRGbXZOQ3lqSXdRSUNpMkNBL2pJQ2ZqbHVuOXdVV2VkMFVhYU9tUUNyVm5kKwpUNWNqbHR3aGJFaFMyNWRrWjUrY2I5Q09VbHhGY1FxZWs1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUCkNacUJQUlZzRi81Y1plQURmcGUxZkJXK3Bkc1FqVnZkK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXEKZWs1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQlcrcGRzUWpWdgpkK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXFlazVxYjgvZWpaQmUrZUFmSTdaQmZFUXMvZk8yQis0CjdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQlcrcGRzUWpWdmQrdDdjalJkOXdkdGVtS2p2UUlaWnJHSTlHVGpNNEYKbXZOQ3lqSXdRSUNpMkNBL2pJQ2ZqbHVuOXdVV2VkMFVhYU9tUUNyVm5kK1Q3Y2psdHdoYkVoUzI1ZGtaNStjYgo5Q09VbHhGY1FxZWs1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmCkJXK3Bkc1FqVnZkK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXFlazVxYjgvZWpaQmUrZUFmSTdaQmYKRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQlcrcGRzUWpWdmQrdDdjalJkOXdkdGVtS2p2UUlaWgpyR0k5R1RqTTRGbXZOQ3lqSXdRSUNpMkNBL2pJQ2ZqbHVuOXdVV2VkMFVhYU9tUUNyVm5kK1Q3Y2psdHdoYkVoClMyNWRrWjUrY2I5Q09VbHhGY1FxZWs1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzUKY1plQURmcGUxZkJXK3Bkc1FqVnZkK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXFlazVxYjgvZWpaQgplK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQlcrcGRzUWpWdmQrdDdjalJkOXdkCnRlbUtqdlFJWlpyR0k5R1RqTTRGbXZOQ3lqSXdRSUNpMkNBL2pJQ2ZqbHVuOXdVV2VkMFVhYU9tUUNyVm5kK1QKN2NqbHR3aGJFaFMyNWRrWjUrY2I5Q09VbHhGY1FxZWs1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQwpacUJQUlZzRi81Y1plQURmcGUxZkJXK3Bkc1FqVnZkK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXFlCms1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQlcrcGRzUWpWdmQKK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXFlazVxYjgvZWpaQmUrZUFmSTdaQmZFUXMvZk8yQis0NwpUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQlcrcGRzUWpWdmQrdDdjalJkOXdkdGVtS2p2UUlaWnJHSTlHVGpNNEZtCnZOQ3lqSXdRSUNpMkNBL2pJQ2ZqbHVuOXdVV2VkMFVhYU9tUUNyVm5kK1Q3Y2psdHdoYkVoUzI1ZGtaNStjYjkKQ09VbHhGY1FxZWs1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQgpXK3Bkc1FqVnZkK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXFlazVxYjgvZWpaQmUrZUFmSTdaQmZFClFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQlcrcGRzUWpWdmQrdDdjalJkOXdkdGVtS2p2UUlaWnIKR0k5R1RqTTRGbXZOQ3lqSXdRSUNpMkNBL2pJQ2ZqbHVuOXdVV2VkMFVhYU9tUUNyVm5kK1Q3Y2psdHdoYkVoUwoyNWRrWjUrY2I5Q09VbHhGY1FxZWs1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjClplQURmcGUxZkJXK3Bkc1FqVnZkK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXFlazVxYjgvZWpaQmUKK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQlcrcGRzUWpWdmQrdDdjalJkOXdkdAplbUtqdlFJWlpyR0k5R1RqTTRGbXZOQ3lqSXdRSUNpMkNBL2pJQ2ZqbHVuOXdVV2VkMFVhYU9tUUNyVm5kK1Q3CmNqbHR3aGJFaFMyNWRrWjUrY2I5Q09VbHhGY1FxZWs1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1oKcUJQUlZzRi81Y1plQURmcGUxZkJXK3Bkc1FqVnZkK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXFlaws1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQlcrcGRzUWpWdmQKK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXFlazVxYjgvZWpaQmUrZUFmSTdaQmZFUXMvZk8yQis0NwpUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQlcrcGRzUWpWdmQrdDdjalJkOXdkdGVtS2p2UUlaWnJHSTlHVGpNNEZtCnZOQ3lqSXdRSUNpMkNBL2pJQ2ZqbHVuOXdVV2VkMFVhYU9tUUNyVm5kK1Q3Y2psdHdoYkVoUzI1ZGtaNStjYjkKQ09VbHhGY1FxZWs1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQgpXK3Bkc1FqVnZkK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXFlazVxYjgvZWpaQmUrZUFmSTdaQmZFClFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQlcrcGRzUWpWdmQrdDdjalJkOXdkdGVtS2p2UUlaWnIKR0k5R1RqTTRGbXZOQ3lqSXdRSUNpMkNBL2pJQ2ZqbHVuOXdVV2VkMFVhYU9tUUNyVm5kK1Q3Y2psdHdoYkVoUwoyNWRrWjUrY2I5Q09VbHhGY1FxZWs1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjClplQURmcGUxZkJXK3Bkc1FqVnZkK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXFlazVxYjgvZWpaQmUKK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQlcrcGRzUWpWdmQrdDdjalJkOXdkdAplbUtqdlFJWlpyR0k5R1RqTTRGbXZOQ3lqSXdRSUNpMkNBL2pJQ2ZqbHVuOXdVV2VkMFVhYU9tUUNyVm5kK1Q3CmNqbHR3aGJFaFMyNWRrWjUrY2I5Q09VbHhGY1FxZWs1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1oKcUJQUlZzRi81Y1plQURmcGUxZkJXK3Bkc1FqVnZkK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXFlaws1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQlcrcGRzUWpWdmQKK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXFlazVxYjgvZWpaQmUrZUFmSTdaQmZFUXMvZk8yQis0NwpUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQlcrcGRzUWpWdmQrdDdjalJkOXdkdGVtS2p2UUlaWnJHSTlHVGpNNEZtCnZOQ3lqSXdRSUNpMkNBL2pJQ2ZqbHVuOXdVV2VkMFVhYU9tUUNyVm5kK1Q3Y2psdHdoYkVoUzI1ZGtaNStjYjkKQ09VbHhGY1FxZWs1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQgpXK3Bkc1FqVnZkK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXFlazVxYjgvZWpaQmUrZUFmSTdaQmZFClFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQlcrcGRzUWpWdmQrdDdjalJkOXdkdGVtS2p2UUlaWnIKR0k5R1RqTTRGbXZOQ3lqSXdRSUNpMkNBL2pJQ2ZqbHVuOXdVV2VkMFVhYU9tUUNyVm5kK1Q3Y2psdHdoYkVoUwoyNWRrWjUrY2I5Q09VbHhGY1FxZWs1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjClplQURmcGUxZkJXK3Bkc1FqVnZkK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXFlazVxYjgvZWpaQmUKK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQlcrcGRzUWpWdmQrdDdjalJkOXdkdAplbUtqdlFJWlpyR0k5R1RqTTRGbXZOQ3lqSXdRSUNpMkNBL2pJQ2ZqbHVuOXdVV2VkMFVhYU9tUUNyVm5kK1Q3CmNqbHR3aGJFaFMyNWRrWjUrY2I5Q09VbHhGY1FxZWs1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1oKcUJQUlZzRi81Y1plQURmcGUxZkJXK3Bkc1FqVnZkK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXFlaws1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQlcrcGRzUWpWdmQKK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXFlazVxYjgvZWpaQmUrZUFmSTdaQmZFUXMvZk8yQis0NwpUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQlcrcGRzUWpWdmQrdDdjalJkOXdkdGVtS2p2UUlaWnJHSTlHVGpNNEZtCnZOQ3lqSXdRSUNpMkNBL2pJQ2ZqbHVuOXdVV2VkMFVhYU9tUUNyVm5kK1Q3Y2psdHdoYkVoUzI1ZGtaNStjYjkKQ09VbHhGY1FxZWs1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQgpXK3Bkc1FqVnZkK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXFlazVxYjgvZWpaQmUrZUFmSTdaQmZFClFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQlcrcGRzUWpWdmQrdDdjalJkOXdkdGVtS2p2UUlaWnIKR0k5R1RqTTRGbXZOQ3lqSXdRSUNpMkNBL2pJQ2ZqbHVuOXdVV2VkMFVhYU9tUUNyVm5kK1Q3Y2psdHdoYkVoUwoyNWRrWjUrY2I5Q09VbHhGY1FxZWs1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjClplQURmcGUxZkJXK3Bkc1FqVnZkK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXFlazVxYjgvZWpaQmUKK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQlcrcGRzUWpWdmQrdDdjalJkOXdkdAplbUtqdlFJWlpyR0k5R1RqTTRGbXZOQ3lqSXdRSUNpMkNBL2pJQ2ZqbHVuOXdVV2VkMFVhYU9tUUNyVm5kK1Q3CmNqbHR3aGJFaFMyNWRrWjUrY2I5Q09VbHhGY1FxZWs1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1oKcUJQUlZzRi81Y1plQURmcGUxZkJXK3Bkc1FqVnZkK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXFlaws1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQlcrcGRzUWpWdmQKK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXFlazVxYjgvZWpaQmUrZUFmSTdaQmZFUXMvZk8yQis0NwpUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQlcrcGRzUWpWdmQrdDdjalJkOXdkdGVtS2p2UUlaWnJHSTlHVGpNNEZtCnZOQ3lqSXdRSUNpMkNBL2pJQ2ZqbHVuOXdVV2VkMFVhYU9tUUNyVm5kK1Q3Y2psdHdoYkVoUzI1ZGtaNStjYjkKQ09VbHhGY1FxZWs1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQgpXK3Bkc1FqVnZkK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXFlazVxYjgvZWpaQmUrZUFmSTdaQmZFClFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQlcrcGRzUWpWdmQrdDdjalJkOXdkdGVtS2p2UUlaWnIKR0k5R1RqTTRGbXZOQ3lqSXdRSUNpMkNBL2pJQ2ZqbHVuOXdVV2VkMFVhYU9tUUNyVm5kK1Q3Y2psdHdoYkVoUwoyNWRrWjUrY2I5Q09VbHhGY1FxZWs1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjClplQURmcGUxZkJXK3Bkc1FqVnZkK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXFlazVxYjgvZWpaQmUKK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQlcrcGRzUWpWdmQrdDdjalJkOXdkdAplbUtqdlFJWlpyR0k5R1RqTTRGbXZOQ3lqSXdRSUNpMkNBL2pJQ2ZqbHVuOXdVV2VkMFVhYU9tUUNyVm5kK1Q3CmNqbHR3aGJFaFMyNWRrWjUrY2I5Q09VbHhGY1FxZWs1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1oKcUJQUlZzRi81Y1plQURmcGUxZkJXK3Bkc1FqVnZkK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXFlaws1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQlcrcGRzUWpWdmQKK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXFlazVxYjgvZWpaQmUrZUFmSTdaQmZFUXMvZk8yQis0NwpUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQlcrcGRzUWpWdmQrdDdjalJkOXdkdGVtS2p2UUlaWnJHSTlHVGpNNEZtCnZOQ3lqSXdRSUNpMkNBL2pJQ2ZqbHVuOXdVV2VkMFVhYU9tUUNyVm5kK1Q3Y2psdHdoYkVoUzI1ZGtaNStjYjkKQ09VbHhGY1FxZWs1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQgpXK3Bkc1FqVnZkK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXFlazVxYjgvZWpaQmUrZUFmSTdaQmZFClFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQlcrcGRzUWpWdmQrdDdjalJkOXdkdGVtS2p2UUlaWnIKR0k5R1RqTTRGbXZOQ3lqSXdRSUNpMkNBL2pJQ2ZqbHVuOXdVV2VkMFVhYU9tUUNyVm5kK1Q3Y2psdHdoYkVoUwoyNWRrWjUrY2I5Q09VbHhGY1FxZWs1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjClplQURmcGUxZkJXK3Bkc1FqVnZkK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXFlazVxYjgvZWpaQmUKK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQlcrcGRzUWpWdmQrdDdjalJkOXdkdAplbUtqdlFJWlpyR0k5R1RqTTRGbXZOQ3lqSXdRSUNpMkNBL2pJQ2ZqbHVuOXdVV2VkMFVhYU9tUUNyVm5kK1Q3CmNqbHR3aGJFaFMyNWRrWjUrY2I5Q09VbHhGY1FxZWs1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1oKcUJQUlZzRi81Y1plQURmcGUxZkJXK3Bkc1FqVnZkK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXFlaws1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQlcrcGRzUWpWdmQKK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXFlazVxYjgvZWpaQmUrZUFmSTdaQmZFUXMvZk8yQis0NwpUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQlcrcGRzUWpWdmQrdDdjalJkOXdkdGVtS2p2UUlaWnJHSTlHVGpNNEZtCnZOQ3lqSXdRSUNpMkNBL2pJQ2ZqbHVuOXdVV2VkMFVhYU9tUUNyVm5kK1Q3Y2psdHdoYkVoUzI1ZGtaNStjYjkKQ09VbHhGY1FxZWs1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQgpXK3Bkc1FqVnZkK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXFlazVxYjgvZWpaQmUrZUFmSTdaQmZFClFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQlcrcGRzUWpWdmQrdDdjalJkOXdkdGVtS2p2UUlaWnIKR0k5R1RqTTRGbXZOQ3lqSXdRSUNpMkNBL2pJQ2ZqbHVuOXdVV2VkMFVhYU9tUUNyVm5kK1Q3Y2psdHdoYkVoUwoyNWRrWjUrY2I5Q09VbHhGY1FxZWs1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjClplQURmcGUxZkJXK3Bkc1FqVnZkK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXFlazVxYjgvZWpaQmUKK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQlcrcGRzUWpWdmQrdDdjalJkOXdkdAplbUtqdlFJWlpyR0k5R1RqTTRGbXZOQ3lqSXdRSUNpMkNBL2pJQ2ZqbHVuOXdVV2VkMFVhYU9tUUNyVm5kK1Q3CmNqbHR3aGJFaFMyNWRrWjUrY2I5Q09VbHhGY1FxZWs1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1oKcUJQUlZzRi81Y1plQURmcGUxZkJXK3Bkc1FqVnZkK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXFlaws1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQlcrcGRzUWpWdmQKK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXFlazVxYjgvZWpaQmUrZUFmSTdaQmZFUXMvZk8yQis0NwpUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQlcrcGRzUWpWdmQrdDdjalJkOXdkdGVtS2p2UUlaWnJHSTlHVGpNNEZtCnZOQ3lqSXdRSUNpMkNBL2pJQ2ZqbHVuOXdVV2VkMFVhYU9tUUNyVm5kK1Q3Y2psdHdoYkVoUzI1ZGtaNStjYjkKQ09VbHhGY1FxZWs1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQgpXK3Bkc1FqVnZkK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXFlazVxYjgvZWpaQmUrZUFmSTdaQmZFClFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjWmVBRGZwZTFmQlcrcGRzUWpWdmQrdDdjalJkOXdkdGVtS2p2UUlaWnIKR0k5R1RqTTRGbXZOQ3lqSXdRSUNpMkNBL2pJQ2ZqbHVuOXdVV2VkMFVhYU9tUUNyVm5kK1Q3Y2psdHdoYkVoUwoyNWRrWjUrY2I5Q09VbHhGY1FxZWs1cWI4L2VqWkJlK2VBZkk3WkJmRVFzL2ZPMkIrNDdUQ1pxQlBSVnNGLzVjClplQURmcGUxZkJXK3Bkc1FqVnZkK3Q3Y2psdHdoYkVoUzI1ZGtaNStjYjlDT1VseEZjUXFlazVxYjgvZWpaQmUKK2