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