AWS [China]: начало

By | 05/03/2017
 

Описание

Продолжение проекта, описанного в посте AWS: билд Java + Maven + Docker + Packer + Terraform – будем разворачивать нечто аналогичное в Китае.

Хотя у Китая есть “свой AWS” – Aliyun.com, принадлежащий Alibaba Group, тем не менее – мы будем пользоваться именно Amazon Web Services.

В этом посте не будет HowTo do something – больше просто описание опыта работы с Китаем.

Пара полезных ссылок:


Сервисы

Первое, что бросается в глаза – это количество сервисов – тут их намного меньше.

Например, консоль в Европе выглядит так:

А в Китае – так:

Список всех сервисов и их наличие по регионам можно посмотреть тут>>>.

Скорость

Вторая проблема – скорость.

Например, открыть страницу китайского AWS, даже просто curl-ом, из Киева:

time curl https://www.amazonaws.cn/en/
...
real    0m30.267s
user    0m0.027s

Тест скорости с iperf из датацентра “Воля” в Киеве:

ubuntu@ip-172-31-14-50:~$ iperf -s
------------------------------------------------------------
Server listening on TCP port 5001
TCP window size: 85.3 KByte (default)
------------------------------------------------------------
[  4] local 172.31.14.50 port 5001 connected with 77.120.103.20 port 36174
[ ID] Interval       Transfer     Bandwidth
[  4]  0.0-53.3 sec   384 KBytes  59.1 Kbits/sec

59.1 Kbits/sec? Где-то такое уже видели, только 56к:

На самом деле скорость варьируется – иногда всё работает более-менее живо, иногда – отмирает напрочь.

ICP license

Ещё один немаловажный (критический, я бы сказал момент) – это ICP license.

Вопросами лицензии занимались менеджеры, потому деталей не знаю, но хороший обзор на эту тему есть тут>>>.

Кратко говоря – вы не можете запустить вебсайт (вообще любой сервис, который работает по портам 80, 443, пока не знаю по поводу 8080 и использует доменное имя), не получив разрешения от властей Китая, а именно – от Ministry of Industry and Information Technology. Не в курсе – как на счёт других сервисов (почта, базы и т.д.), но что касается веб – без лицензии не обойтись.

Пример лицензии можно увидеть тут – http://bj.58.com, слева внизу:

Или даже на странице самого китайского AWS Console:

Процесс получения лицезии выглядит примерно так:

Начало работы

Начнём работу с настройки профиля:

aws configure --profile tag-cn
AWS Access Key ID [None]: AKI***L5A
AWS Secret Access Key [None]: OtN***7Cb
Default region name [None]: cn-north-1
Default output format [None]: json

Образы Ubuntu, как обычно – можно найти на Ubuntu Amazon EC2 AMI Finder.

И первый “упс” – в Китае нет t2.nano:

aws ec2 run-instances --image-id ami-a163b4cc --key-name tag-cn --instance-type t2.nano --profile tag-cn
An error occurred (Unsupported) when calling the RunInstances operation: The requested configuration is currently not supported. Please check the documentation for supported configurations.

Docker test

Запускаем интанс:

aws ec2 run-instances --image-id ami-a163b4cc --key-name tag-cn --instance-type t2.micro --profile tag-cn

Первое, что требуется проверить – скорость загрузки образов с серверов JFrog Artifactory, которые расположены в Европе.

Планируется использование уже имеющегося Jenkins в Европе, который будет собирать образы и пушить их в Artifactory, после чего скрипт на китайских инстансах будет делать docker pull и переключать Blue и Green окружения.

Устанавливаем Docker:

time wget -qO- https://get.docker.com/ | sh

Скорость… При apt-get update, даже несмотря на то, что большая часть данных тянется из китайского репозитория Ubuntu (http://cn-north-1b.clouds.archive.ubuntu.com/ubuntu) – update выполнялся минут 10, а весь процесс установки Docker из этого скрипта – минут 30.

Ждём, несколько раз отлавливая ошибки вида:


E: Failed to fetch https://apt.dockerproject.org/repo/pool/main/d/docker-engine/docker-engine_17.04.0~ce-0~ubuntu-xenial_amd64.deb Operation too slow. Less than 10 bytes/sec transferred the last 120 seconds

Собственно – попытка pull:

root@ip-172-31-14-50:~# time docker pull engineering-tag-docker.jfrog.io/tag-configuration:production-rc_2017april-24
production-rc_2017april-24: Pulling from tag-configuration
ec37562cf8fa: Pull complete
2f029489f597: Pull complete
c274fc74f91c: Pull complete
9ed2daf3bbcb: Pull complete
1e68211e62fb: Pull complete
Digest: sha256:6c9d700f8d0c4c59ba693ffed1bb23c06ef5f573b71e86d911471e8f054d208a
Status: Downloaded newer image for engineering-tag-docker.jfrog.io/tag-configuration:production-rc_2017april-24
real    7m48.104s
user    0m0.072s
sys     0m0.024s

Почти 8 минут для образа в 237 мб – для нас приемлемо, тем более последующие загрузки будут быстрее.

Terraform

Для создания окружений (и для деплоя, но не в этом случае) – у нас имеются шаблоны Terrafrom:

ls -l ../../tag-server-api-infrastructure/terraform
total 104
-rw-r--r-- 1 setevoy setevoy 5582 Dec 27 16:24 api.tf
drwxr-xr-x 2 setevoy setevoy 4096 Feb 16 12:21 autoscaling_group_blue
drwxr-xr-x 2 setevoy setevoy 4096 Dec 27 16:24 autoscaling_group_green
drwxr-xr-x 2 setevoy setevoy 4096 Dec 27 16:24 autoscaling_policy
drwxr-xr-x 2 setevoy setevoy 4096 Dec 27 16:24 elb
-rw-r--r-- 1 setevoy setevoy 3271 Dec 27 16:24 eureka.tf
drwxr-xr-x 3 setevoy setevoy 4096 Dec 27 16:24 files
drwxr-xr-x 2 setevoy setevoy 4096 May  3 15:52 launch_configuration
drwxr-xr-x 2 setevoy setevoy 4096 Dec 27 16:24 nat
-rw-r--r-- 1 setevoy setevoy  648 Dec 27 16:24 nat.tf
-rw-r--r-- 1 setevoy setevoy  128 Dec 27 16:24 provider.tf
-rw-r--r-- 1 setevoy setevoy 3072 Feb 20 14:15 security_group_api_ec2.tf
-rw-r--r-- 1 setevoy setevoy 2238 Dec 27 16:24 security_group_api_elb.tf
-rw-r--r-- 1 setevoy setevoy  395 Dec 27 16:24 security_group_default.tf
-rw-r--r-- 1 setevoy setevoy  710 Dec 27 16:24 security_group_eureka.tf
-rw-r--r-- 1 setevoy setevoy 1546 Dec 27 16:24 security_group_http_out.tf
-rw-r--r-- 1 setevoy setevoy 2347 Feb 20 14:15 security_group_nat.tf
-rw-r--r-- 1 setevoy setevoy  786 Dec 27 16:24 security_group_ssh_private.tf
-rw-r--r-- 1 setevoy setevoy  409 Dec 27 16:24 security_group_ssh_trusted.tf
-rwxr-xr-x 1 setevoy setevoy 3203 May  3 14:46 terraform-cn.sh
-rw-r--r-- 1 setevoy setevoy 3654 May  3 14:49 variables.tf
-rw-r--r-- 1 setevoy setevoy  131 Dec 27 16:24 vpc_internet_gateway.tf
-rw-r--r-- 1 setevoy setevoy 1224 Dec 27 16:24 vpc_route_table.tf
-rw-r--r-- 1 setevoy setevoy  975 Dec 27 16:24 vpc_subnets.tf
-rw-r--r-- 1 setevoy setevoy  126 Dec 27 16:24 vpc.tf

А для быстрого запуска – я когда-то писал bash-скрипт:

#!/usr/bin/env bash

# Do NOT use thi script ever!
# For testing environmtnt only

AWS_ACCESS_KEY_ID="AKI***L5A"
AWS_SECRET_ACCESS_KEY="OtN***7Cb"
AWS_REGION="cn-north-1"

USERNAME="docker"
PASSWORD="M8f***XSC"

DOCKER_TAG=$1

[[ -z $DOCKER_TAG ]] && { echo "Specify Docker tag as first argument."; exit 1; }

TF_BACK_PATH="dev-cn"
EC2KEY="tag-cn"

VPC_CIDR="10.0.0.0/16"

SPRING_PROFILE=dev-cn

terraform get

terraform_config () {

    terraform remote config \
        -backend=artifactory \
        -backend-config="username=${USERNAME}" \
        -backend-config="password=${PASSWORD}" \
        -backend-config="url=https://engineering.artifactoryonline.com/engineering/tag-terraform/" \
        -backend-config="repo=api" \
        -backend-config="subpath=${TF_BACK_PATH}"
}

terraform_plan () {

    terraform plan \
        -var region=${AWS_REGION} \
        -var aws_access_key=${AWS_ACCESS_KEY_ID} \
        -var aws_secret_key=${AWS_SECRET_ACCESS_KEY} \
        -var ssh_key_name=${EC2KEY} \
        -var vpc_cidr_block=${VPC_CIDR} \
        -var 'public_subnet_cidr_blocks={ "0" = "10.0.0.0/24", "1" = "10.0.1.0/24" }' \
        -var 'private_subnet_cidr_blocks={ "0" = "10.0.2.0/24", "1" = "10.0.3.0/24" }' \
        -var spring_profile=${SPRING_PROFILE} \
        -var docker_image_tag=${DOCKER_TAG} \
        -var min_size_green=1 \
        -var min_size_blue=0 \
        -var max_size=8
}

terraform_apply () {

    terraform apply \
        -var region=${AWS_REGION} \
        -var aws_access_key=${AWS_ACCESS_KEY_ID} \
        -var aws_secret_key=${AWS_SECRET_ACCESS_KEY} \
        -var ssh_key_name=${EC2KEY} \
        -var vpc_cidr_block=${VPC_CIDR} \
        -var 'public_subnet_cidr_blocks={ "0" = "10.0.0.0/24", "1" = "10.0.1.0/24" }' \
        -var 'private_subnet_cidr_blocks={ "0" = "10.0.2.0/24", "1" = "10.0.3.0/24" }' \
        -var spring_profile=${SPRING_PROFILE} \
        -var docker_image_tag=${DOCKER_TAG}
}

terraform_plan_destroy () {

    terraform plan -destroy \
        -var region=${AWS_REGION} \
        -var aws_access_key=${AWS_ACCESS_KEY_ID} \
        -var aws_secret_key=${AWS_SECRET_ACCESS_KEY} \
        -var ssh_key_name=${EC2KEY} \
        -var vpc_cidr_block=${VPC_CIDR} \
        -var 'public_subnet_cidr_blocks={ "0" = "10.0.0.0/24", "1" = "10.0.1.0/24" }' \
        -var 'private_subnet_cidr_blocks={ "0" = "10.0.2.0/24", "1" = "10.0.3.0/24" }' \
        -var spring_profile=${SPRING_PROFILE}
}

terraform_destroy () {

    terraform destroy \
        -var region=${AWS_REGION} \
        -var aws_access_key=${AWS_ACCESS_KEY_ID} \
        -var aws_secret_key=${AWS_SECRET_ACCESS_KEY} \
        -var ssh_key_name=${EC2KEY} \
        -var vpc_cidr_block=${VPC_CIDR} \
        -var 'public_subnet_cidr_blocks={ "0" = "10.0.0.0/24", "1" = "10.0.1.0/24" }' \
        -var 'private_subnet_cidr_blocks={ "0" = "10.0.2.0/24", "1" = "10.0.3.0/24" }' \
        -var spring_profile=${SPRING_PROFILE}
}

#terraform_config || exit 1
#terraform_plan || exit 1
terraform_apply || exit 1
#terraform_plan_destroy || exit 1
#terraform_destroy || exit 1

Запускаем, пробуем:

./terraform-cn.sh production-rc_2017april-24
Get: file:///home/setevoy/Work/LON.TAG/tag-server-api-infrastructure/terraform/launch_configuration
...
Get: file:///home/setevoy/Work/LON.TAG/tag-server-api-infrastructure/terraform/nat
...
data.template_file.eureka_userdata: Refreshing state...
data.template_file.api_userdata: Refreshing state...
data.aws_ami.nat: Refreshing state...
data.aws_ami.eureka_blue: Refreshing state...
data.aws_ami.api_blue: Refreshing state...
data.aws_ami.api_green: Refreshing state...
data.aws_ami.eureka_green: Refreshing state...
Error refreshing state: 1 error(s) occurred:
* data.aws_ami.eureka_green: 1 error(s) occurred:
* data.aws_ami.eureka_green: data.aws_ami.eureka_green: AuthFailure: AWS was not able to validate the provided access credentials
status code: 401, request id: 76509ce4-e07c-42b2-bdbf-a4e80e877d1c

Странно, но ок – добавляем AIM роль AdministratorAccess, пробуем снова (прим. – роль администратора не помогла, см. ниже).

Вторая ошибка – из-за соединения. Работа из Киева в Китай будет аукаться ещё много раз:


* aws_security_group.http_out: Error waiting for Security Group (sg-e7fa5f83) to become available: timeout while waiting for state to become ‘exists’ (timeout: 1m0s)

Перезапускаем.

Проблемы

Ещё одна ошибка:

Просто консоль не сумела подгрузить данные. Ну, ок…

Вот ещё – Connection reset:

Ещё ошибка:

А ещё можем так:

Так мы и закончили первый день… 🙂

Ещё несколько раз выскакивала ошибка вида:


* data.aws_ami.eureka_green: data.aws_ami.eureka_green: AuthFailure: AWS was not able to validate the provided access credentials
status code: 401, request id: c534dca9-d35f-408c-a310-86bf1bfc53dc

Но перезапуск помогал. Причём появляется она рандомно, независимо от типа ресурса – иногда при создании VPC, иногда – EC2 интанса.

Продолжение тут>>>.