Docker — ECR login

Elastic Container Registry

AIM -> Users

Choose "Programmatic access" -> Next

Choose "Attach existing policies directly" -> "Create Policy"

And add next:

Read all repo:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "ecr:GetLifecyclePolicyPreview",
                "ecr:GetDownloadUrlForLayer",
                "ecr:BatchGetImage",
                "ecr:DescribeImages",
                "ecr:DescribeRepositories",
                "ecr:ListTagsForResource",
                "ecr:ListImages",
                "ecr:BatchCheckLayerAvailability",
                "ecr:GetLifecyclePolicy",
                "ecr:GetRepositoryPolicy"
            ],
            "Resource": "*"
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": "ecr:GetAuthorizationToken",
            "Resource": "*"
        }
    ]
}

############### Read only one repo ##################

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "ecr:GetLifecyclePolicyPreview",
                "ecr:GetDownloadUrlForLayer",
                "ecr:BatchGetImage",
                "ecr:DescribeImages",
                "ecr:DescribeRepositories",
                "ecr:ListTagsForResource",
                "ecr:ListImages",
                "ecr:BatchCheckLayerAvailability",
                "ecr:GetLifecyclePolicy",
                "ecr:GetRepositoryPolicy"
            ],
            "Resource": "arn:aws:ecr:eu-west-1:111111111111:repository/artem-repo"
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": "ecr:GetAuthorizationToken",
            "Resource": "*"
        }
    ]
}

eu-west-1 — region
111111111111 — registry ID
artem-repo — repository name

Save "Access key ID" and "Secret access key"

XXXXXXXXXXXXXXXXXXXX

YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY

sudo apt update
sudo apt install make

Для следующего шага должен быть установлен Docker

cd /tmp && git clone https://github.com/awslabs/amazon-ecr-credential-helper.git
cd amazon-ecr-credential-helper && sudo make docker
sudo cp -a bin/local/docker-credential-ecr-login /usr/bin/
mkdir ~/.docker/
vim ~/.docker/config.json

And add next:

{
	"credsStore": "ecr-login"
}

Если не установлен AWS-Cli

sudo apt install awscli
aws configure

И указываем "Access key ID" and "Secret access key"

MySQL — Основные команды

Создать базу данных, пользователя и предоставить ему полный доступ к базе:

CREATE DATABASE database_name CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE USER 'user_name'@'%' IDENTIFIED BY 'PASSWORD';
GRANT ALL PRIVILEGES ON database_name.* TO 'user_name'@'%';
FLUSH PRIVILEGES;

Для того, чтобы разрешить подключения к базе только локально, нужно:

'user_name'@'%'

заменить на:

'user_name'@'localhost'

Удалить все права пользователя на базу:

REVOKE ALL ON database_name.* FROM 'user_name'@'localhost';

Делаем дамп базы:

mysqldump -u user_name -p database_name > database_name.sql

Заливаем дамп:

mysql -u user_name -p database_name < database_name.sql

Список всех пользователей:

SELECT User,Host FROM mysql.user;

Создаем Read-Only пользователя для одной базы:

CREATE USER 'readonly_user_name'@'%' IDENTIFIED BY 'password';
GRANT SELECT ON database_name.* TO 'readonly_user_name'@'%';

FIX ERROR — Docker: Err http://http.debian.net jessie-backports/main amd64 Packages

При попытке обновить список репозиториев в Docker образе основанного на "node:8" появляется следующая ошибка:

Err http://http.debian.net jessie-backports/main amd64 Packages

Решение

Dockerfile:
FROM node:8

RUN echo "deb [check-valid-until=no] http://cdn-fastly.deb.debian.org/debian jessie main" > /etc/apt/sources.list.d/jessie.list && \
    echo "deb [check-valid-until=no] http://archive.debian.org/debian jessie-backports main" > /etc/apt/sources.list.d/jessie-backports.list && \
    sed -i '/deb http:\/\/deb.debian.org\/debian jessie-updates main/d' /etc/apt/sources.list && \
    apt-get -o Acquire::Check-Valid-Until=false update

Fastlane — TestFlight: Invalid App Store Icon

При заливке в TestFlight Fastlane выдает следующее:

[Transporter Error Output]: ERROR ITMS-90717: "Invalid App Store Icon. The App Store Icon in the asset catalog in 'your_app.app' can't be transparent nor contain an alpha channel."
Transporter transfer failed.

ERROR ITMS-90717: "Invalid App Store Icon. The App Store Icon in the asset catalog in 'your_app.app' can't be transparent nor contain an alpha channel."
[iTMSTransporter]

DBG-X: parameter ErrorCode = 1102

[iTMSTransporter]

DBG-X: parameter ErrorMessage = ERROR ITMS-90717: "Invalid App Store Icon. The App Store Icon in the asset catalog in 'your_app.app' can't be transparent nor contain an alpha channel.

[iTMSTransporter] (1102)

[iTMSTransporter]

ERROR: ERROR ITMS-90717: "Invalid App Store Icon. The App Store Icon in the asset catalog in 'your_app.app' can't be transparent nor contain an alpha channel."

[iTMSTransporter]

DBG-X: The error code is: 1102

[iTMSTransporter]

INFO: Done performing authentication.

 

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

brew install imagemagick

Удалим альфа канал с иконок приложения:

find ./ios/your_app/Images.xcassets/AppIcon.appiconset/ -name "*.png" -exec convert "{}" -alpha off "{}" \;

Строка для Jenkins'а с экранированием:

sh "find ./ios/your_app/Images.xcassets/AppIcon.appiconset/ -name \"*.png\" -exec convert \"{}\" -alpha off \"{}\" \\;"

Jenkins — Нагрузочное тестирование (JMeter+Ant+Slack)

На сервер с Jenkins скачиваем JMeter

Так же понадобится JMeterPluginsCMD

Создадим директорию для хранения:

mkdir -p /var/lib/jmeter

Скачаем и разархивируем в эту директорию содержимое двух архивов.

Чтобы структура была следующая:

root@jenkins:~# ll /var/lib/jmeter/
total 64K
drwxr-xr-x  8 jenkins jenkins 4.0K Apr 24 15:39 .
drwxr-xr-x 37 root    root    4.0K Mar 22 10:29 ..
drwxr-xr-x  5 jenkins jenkins 4.0K Apr 24 17:47 bin
drwxr-xr-x  5 jenkins jenkins 4.0K Mar 10 08:41 docs
drwxr-xr-x  2 jenkins jenkins 4.0K Mar 10 08:43 extras
drwxr-xr-x  4 jenkins jenkins 4.0K Apr 24 17:47 lib
-rw-r--r--  1 jenkins jenkins  15K Mar 10 10:08 LICENSE
drwxr-xr-x  4 jenkins jenkins 4.0K Mar 10 10:08 licenses
-rw-r--r--  1 jenkins jenkins  172 Mar 10 10:08 NOTICE
drwxr-xr-x  6 jenkins jenkins 4.0K Mar 10 09:58 printable_docs
-rw-r--r--  1 jenkins jenkins  10K Mar 10 10:08 README.md

Читать далее "Jenkins — Нагрузочное тестирование (JMeter+Ant+Slack)"

Kubernetes — Ingress несколько бекендов

Пример конфигурации Kubernetes Ingress с выбором бекенда на основе значения аргумента "proxy". И дефолтным бекендом, если значение аргумента "proxy" отличное от "1" и "2", или отсутствует.

manifest.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: artem-test-proxy-0-app
  namespace: staging
  labels:
    app: artem-test-proxy-0-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: artem-test-proxy-0-app
  strategy:
    type: RollingUpdate
  progressDeadlineSeconds: 300
  minReadySeconds: 60
  template:
    metadata:
      labels:
        app: artem-test-proxy-0-app
    spec:
      containers:
      - name: artem-test-proxy-0
        image: dockersamples/static-site
        env:
        - name: AUTHOR
          value: Default
        ports:
        - containerPort: 80
      nodeSelector:
        nodegroup: staging
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: artem-test-proxy-1-app
  namespace: staging
  labels:
    app: artem-test-proxy-1-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: artem-test-proxy-1-app
  strategy:
    type: RollingUpdate
  progressDeadlineSeconds: 300
  minReadySeconds: 60
  template:
    metadata:
      labels:
        app: artem-test-proxy-1-app
    spec:
      containers:
      - name: artem-test-proxy-1
        image: dockersamples/static-site
        env:
        - name: AUTHOR
          value: Proxy=1
        ports:
        - containerPort: 80
      nodeSelector:
        nodegroup: staging
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: artem-test-proxy-2-app
  namespace: staging
  labels:
    app: artem-test-proxy-2-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: artem-test-proxy-2-app
  strategy:
    type: RollingUpdate
  progressDeadlineSeconds: 300
  minReadySeconds: 60
  template:
    metadata:
      labels:
        app: artem-test-proxy-2-app
    spec:
      containers:
      - name: artem-test-proxy-2
        image: dockersamples/static-site
        env:
        - name: AUTHOR
          value: Proxy=2
        ports:
        - containerPort: 80
      nodeSelector:
        nodegroup: staging

---

apiVersion: v1
kind: Service
metadata:
  name: artem-test-proxy-0-svc
  namespace: staging
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: artem-test-proxy-0-app
---
apiVersion: v1
kind: Service
metadata:
  name: artem-test-proxy-1-svc
  namespace: staging
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: artem-test-proxy-1-app
---
apiVersion: v1
kind: Service
metadata:
  name: artem-test-proxy-2-svc
  namespace: staging
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: artem-test-proxy-2-app

---

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: artem-test-proxy-ing
  namespace: staging
  annotations:
    kubernetes.io/ingress.class: ingress-staging
    certmanager.k8s.io/cluster-issuer: letsencrypt-prod
    certmanager.k8s.io/acme-challenge-type: dns01
    certmanager.k8s.io/acme-dns01-provider: dns
    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/configuration-snippet: |
                    if ($arg_proxy = 1) {
                      proxy_pass http://artem-test-proxy-1-svc.staging.svc.cluster.local;
                    }
                    if ($arg_proxy = 2) {
                      proxy_pass http://artem-test-proxy-2-svc.staging.svc.cluster.local;
                    }
spec:
  tls:
  - hosts:
    - artem.services
    secretName: artem.services-secret-tls
  rules:
  - host: artem.services
    http:
      paths:
      - path: /
        backend:
          serviceName: artem-test-proxy-0-svc
          servicePort: 80

Jenkins — Деплой в Docker Swarm используя stack deploy

Пример деплоя в Docker Swarm с Jenkins'а используя stack deploy.

Jenkinsfile:

pipeline {
    agent any
    environment {
        PROJECT_NAME = 'artem-api'
        SLACK_CHANNEL = 'maintenance-artem-api'
        SWARM_MANAGER_IP = '8.8.8.8'
        SWARM_WORKER_1_IP = '1.1.1.1'
        SWARM_WORKER_2_IP = '2.2.2.2'
        TLS_CA = '/var/lib/jenkins/TLS/swarm/ca.pem'
        TLS_CERT = '/var/lib/jenkins/TLS/swarm/cert.pem'
        TLS_KEY = '/var/lib/jenkins/TLS/swarm/key.pem'
        ECR = '111111111111.dkr.ecr.us-west-1.amazonaws.com/artem'
        PROFILE = 'artem'
    }
    stages {
        stage ('Auth to AWS ECR.') {
            steps {
                sh "echo 'Auth to image repo'"
                sh "eval \$(aws ecr get-login --profile ${PROFILE} --no-include-email) &>/dev/null"
            }
        }
        stage ('Build image'){
            steps{
                script{
                    withDockerServer([uri:'tcp://127.0.0.1:4243']) {
                        sh "cp ./.jenkins/Dockerfile ./Dockerfile"
                        echo "Debug: Building  with ${ECR}:${PROJECT_NAME}-${JOB_BASE_NAME}-${BUILD_NUMBER}"
                        def image = docker.build ("${ECR}:${PROJECT_NAME}-${JOB_BASE_NAME}-${BUILD_NUMBER}")
                        image.push ()
                        echo "Debug: After push to registry"
                    }
                }
            }
        }
        stage ('Update API on Staging') {
            when { branch 'staging' }
            steps {
                sh 'envsubst < ".jenkins/Staging.yml" > "Staging.yml"'
                sh "ssh ubuntu@${SWARM_WORKER_1_IP} 'sudo docker pull ${ECR}:${PROJECT_NAME}-${JOB_BASE_NAME}-${BUILD_NUMBER}'"
                sh "ssh ubuntu@${SWARM_WORKER_2_IP} 'sudo docker pull ${ECR}:${PROJECT_NAME}-${JOB_BASE_NAME}-${BUILD_NUMBER}'"
                sh "docker -H tcp://${SWARM_MANAGER_IP}:2376 --tlsverify --tlscacert=${TLS_CA} --tlscert=${TLS_CERT} --tlskey=${TLS_KEY} stack deploy --compose-file Staging.yml artem-api"
            }
        }
        stage ('Update API on Production') {
            when { branch 'production' }
            steps {
                sh 'envsubst < ".jenkins/Production.yml" > "Production.yml"'
                sh "ssh ubuntu@${SWARM_WORKER_1_IP} 'sudo docker pull ${ECR}:${PROJECT_NAME}-${JOB_BASE_NAME}-${BUILD_NUMBER}'"
                sh "ssh ubuntu@${SWARM_WORKER_2_IP} 'sudo docker pull ${ECR}:${PROJECT_NAME}-${JOB_BASE_NAME}-${BUILD_NUMBER}'"
                sh "docker -H tcp://${SWARM_MANAGER_IP}:2376 --tlsverify --tlscacert=${TLS_CA} --tlscert=${TLS_CERT} --tlskey=${TLS_KEY} stack deploy --compose-file Production.yml artem-api"
            }
        }
    }
    post {
        success {
            slackSend channel: "${SLACK_CHANNEL}", color: 'good', message: "Job: ${JOB_NAME}${BUILD_NUMBER} build was successful."
        }
        failure {
            slackSend channel: "${SLACK_CHANNEL}", color: 'danger', message: "Job: ${JOB_NAME}${BUILD_NUMBER} was finished with some error. It may occurs because of the build was rollbacked by docker swarm, or because of other error (watch the Jenkins Console Output): ${JOB_URL}${BUILD_ID}/consoleFull"
        }
        unstable {
            slackSend channel: "${SLACK_CHANNEL}", color: 'warning', message: "Job: ${JOB_NAME}${BUILD_NUMBER} was finished with some error. Please watch the Jenkins Console Output: ${JOB_URL}${BUILD_ID}/console."
        }
    }
}

Читать далее "Jenkins — Деплой в Docker Swarm используя stack deploy"

Jenkins — Pipeline credentials

 

Создадим "Credentials" с типом "Secret text". Заполним ID и добавим секрет, описание опционально.

В Jenkinsfile добавим следующее:

pipeline {
    agent none
    environment {
        MY_PASSWORD = credentials('my-secret-password')
    }

После этого можно использовать переменную "MY_PASSWORD", не боясь того, что он будет показан открытым текстом.