FIX ERROR — Docker Node: error while loading shared libraries: libX11-xcb.so.1

При попытке запустить "chrome" в Docker образе "Node" получил следующую ошибку:

error while loading shared libraries: libX11-xcb.so.1: cannot open shared object file: No such file or directory

Решение

Dockerfile:
FROM node:10

RUN apt-get update && apt-get install -y \
  build-essential \
  libssl-dev \
  imagemagick \
  wget \
  unzip \
  fontconfig \
  locales \
  gconf-service \
  libasound2 \
  libatk1.0-0 \
  libc6 \
  libcairo2 \
  libcups2 \
  libdbus-1-3 \
  libexpat1 \
  libfontconfig1 \
  libgcc1 \
  libgconf-2-4 \
  libgdk-pixbuf2.0-0 \
  libglib2.0-0 \
  libgtk-3-0 \
  libnspr4 \
  libpango-1.0-0 \
  libpangocairo-1.0-0 \
  libstdc++6 \
  libx11-6 \
  libx11-xcb1 \
  libxcb1 \
  libxcomposite1 \
  libxcursor1 \
  libxdamage1 \
  libxext6 \
  libxfixes3 \
  libxi6 \
  libxrandr2 \
  libxrender1 \
  libxss1 \
  libxtst6 \
  ca-certificates \
  fonts-liberation \
  libappindicator1 \
  libnss3 \
  lsb-release \
  xdg-utils \
  wget \
  libx11-xcb-dev \
  libatk-bridge2.0-0 && \
  rm -rf /var/lib/apt/lists/*

Fastlane — Two-Factor Authentication Apple Developer

 

Чтобы автоматизировать сборку iOS приложения через Fastlane и не вводить постоянно код из СМС, нужно получить куки и использовать их.

Для начала нужно выполнить логин через браузер. Получаем код из СМС и запоминаем его.

Логинимся на MacOS сборщике:

fastlane spaceauth -u [email protected]

Вводим пароль и код из СМС.

После чего в директории:

/Users/admin/.fastlane/spaceship/[email protected]

 

admin — имя моего пользователя

Появится файл "cookie". Если у вас больше одного сборщика, то нужно позаботится о том, чтобы этот файл был на всех сборщиках.

Чтобы автоматизировать сборку через Jenkins, достаточно добавить следующие строки перед сборкой iOS приложения:

sh 'FASTLANE_DISABLE_COLORS=1 FASTLANE_PASSWORD=MyPassword1234 fastlane spaceauth -u [email protected] | tail -n 1 > 2fa.file'
sh 'eval $(cat 2fa.file)'

FIX ERROR — npm: Couldn’t follow symbolic link

При сборке мобильного приложения для Android на Ubuntu получил следующую ошибку:

FAILURE: Build failed with an exception.

* What went wrong:
Failed to capture fingerprint of input files for task ':app:bundleReleaseJsAndAssets' property '$1' during up-to-date check.
> Could not list contents of '/var/lib/jenkins/workspace/myapp_develop_0.0.1/node_modules/react-native-interactable/{ios,android}'. Couldn't follow symbolic link.

Если вывести содержимое директории "node_modules/react-native-interactable" то видим следующее:

ll node_modules/react-native-interactable/
total 268K
drwxr-xr-x   5 jenkins jenkins 4.0K Mar 28 09:40 .
drwxr-xr-x 866 jenkins jenkins  36K Mar 28 09:40 ..
drwxr-xr-x   2 jenkins jenkins 4.0K Mar 28 09:40 .ghp
-rw-r--r--   1 jenkins jenkins   35 Mar 28 09:40 index.android.js
-rw-r--r--   1 jenkins jenkins   31 Mar 28 09:40 index.ios.js
-rw-r--r--   1 jenkins jenkins  569 Mar 28 09:40 Interactable.podspec
lrwxrwxrwx   1 jenkins jenkins   17 Mar 28 09:40 {ios,android} -> lib/{ios,android}
drwxr-xr-x   5 jenkins jenkins 4.0K Mar 28 09:40 lib
-rw-r--r--   1 jenkins jenkins 1.1K Mar 28 09:40 LICENSE
-rw-r--r--   1 jenkins jenkins 1.3K Mar 28 09:40 package.json
-rw-r--r--   1 jenkins jenkins  12K Mar 28 09:40 PROPS.md
-rw-r--r--   1 jenkins jenkins  16K Mar 28 09:40 README.md
-rw-r--r--   1 jenkins jenkins  276 Mar 28 09:40 SUPPORT.md
drwxr-xr-x   2 jenkins jenkins 4.0K Mar 28 09:40 typings
-rw-r--r--   1 jenkins jenkins 1.7K Mar 28 09:40 UX-INSPIRATIONS.md
-rw-r--r--   1 jenkins jenkins 159K Mar 28 09:40 yarn.lock

Решение

Для npm

npm config set script-shell "/bin/bash"

Для yarn

yarn config set script-shell "/bin/bash"

 

Удаляем директорию "node_modules" и запускаем npm или yarn.

После этого линк должен выглядеть следующем образом:

lrwxrwxrwx   1 jenkins jenkins   11 Mar 28 09:38 android -> lib/android
lrwxrwxrwx   1 jenkins jenkins    7 Mar 28 09:38 ios -> lib/ios

FIX ERROR — Fastlane: ITSAppUsesNonExemptEncryption

В Fastlane при попытке залить приложение в TestFlight появляется следующая ошибка:

Set 'ITSAppUsesNonExemptEncryption' in the 'Info.plist' to skip this step and speed up the submission

 

Решение

Добавить в файл "Info.plist", который находится по пути "ios/NAME_OF_YOUR_POROJECT/Info.plist" следующее:

<key>ITSAppUsesNonExemptEncryption</key>
	<false/>

Jenkins — NodeJS + Nginx

Пример MultibranchPipeline сборки и деплоя NodeJS при помощи Jenkins'а, упаковывание собранного в контейнер с Nginx'ом и обновлением образа в Kubernetes. В качестве хранилища образов используется AWS ECR, уведомления о сборке отправляются в SLACK канал.

Jenkinsfile:

pipeline{
    parameters {
        booleanParam(name: 'del_cache', defaultValue: false, description: 'Toggle this value to build with cache clearing.')
    }
    agent any
    environment {
        SLACK_CHANNEL = '#maintenance-test'
        IMAGE_REPO = 'XXXXXXXXXXXX.dkr.ecr.eu-west-1.amazonaws.com/artem'
        KUBECTL = 'kubectl --kubeconfig=/var/lib/jenkins/.kube/k8s-artem.yml'
        PROJECT_NAME = 'test-web'
        REPO = 'https://git.artem.services/scm/dev/test-web.git'
        REPO_CRED = 'svc-bitbucket'
    }
    options {
        ansiColor('xterm')
        timeout(time: 30, unit:'MINUTES')
        timestamps()
    }
    stages {
        stage ('Authorization in repo') {
            steps {
                script {
                    sh 'eval "$(aws ecr get-login --profile artem --region eu-west-1 --no-include-email)" &> /dev/null'
                }
            }
        }
        stage ('Delete Work Dir') {
            when { expression { return params.del_cache } }
            steps {
                deleteDir()
                git branch: "${BRANCH_NAME}", credentialsId: "${REPO_CRED}", url: "${REPO}"
            }
        }
        stage ('Build app') {
            agent {
                docker {
                    image 'node:latest'
                    args "--name ${BUILD_TAG}-app \
                    -v /etc/passwd:/etc/passwd:ro"
                    reuseNode true                
                }
            }
            environment {
                HOME = "${WORKSPACE}"
            }
            steps {
                sh "npm install"
                sh "npm run build"
            }
        }
        stage ('Build app image') {
            steps {
                script {
                    withDockerServer([uri:'tcp://127.0.0.1:4243']) {
                        sh 'eval "$(aws ecr get-login --profile artem --region eu-west-1 --no-include-email)" &> /dev/null'
                        echo "Debug: Building  with docker.build(${IMAGE_REPO}:${PROJECT_NAME}-${JOB_BASE_NAME}-${BUILD_NUMBER})"
                        sh "cp ./.jenkins/Dockerfile ./Dockerfile"
                        def image = docker.build ("${IMAGE_REPO}:${PROJECT_NAME}-${JOB_BASE_NAME}-${BUILD_NUMBER}")
                        echo "Debug: Before push to registry"
                        image.push ()
                        echo "Debug: After push to registry"
                    }
                }
            }
        }
        stage ('Deploy on staging.') {
            when { branch 'staging' }
            steps {
                sh "${KUBECTL} -n staging set image deployment.v1.apps/${PROJECT_NAME}-app ${PROJECT_NAME}=${IMAGE_REPO}:${PROJECT_NAME}-${JOB_BASE_NAME}-${BUILD_NUMBER} --record"
            }
        }
    }
    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 — NodeJS + Nginx"

Kubernetes — Ingress запрет индексирования поисковым ботам

Для того, чтобы поисковые боты не индексировали staging среду, в "Config Map" Ingress'а добавим следующий блок:

http-snippet: |
  map $http_user_agent $search_bots {
    default 0;
    ~*(google|bing|yandex|msnbot) 1;
  }

 

Затем в для каждого ресурса, которому нужно запретить индексирование в Ingress добавим следующий блок:

nginx.ingress.kubernetes.io/server-snippet: |
  if ($search_bots = 1) {
    return 403;
  }

 

Для проверки можно воспользоваться утилитой cURL

curl -L -A "Googlebot/2.1 (+http://www.google.com/bot.html)" your_site.com

Kubernetes — Очистка раздела пода Postgres при удалении

Задача следующая, удалять содержимое Persistent Storage для пода с Postgres базой данных при включенной опции при сборке в Jenkins.

Читать далее "Kubernetes — Очистка раздела пода Postgres при удалении"

Kubernetes — Пример манифеста пода с двумя контейнерами

Пример двух контейнеров в одном поде, где первый контейнер с приложением, а второй — Nginx, который проксирует на контейнер с приложением. Так же контейнеры используют общую директорию.

manifest.yml

apiVersion: v1
kind: ConfigMap
metadata:
  name: example-config
  namespace: staging
  labels:
    app: example-app
data:
  POSTGRES_USER: "pg_user"
  POSTGRES_DB: "pg_db"
  POSTGRES_PASSWORD: "password"
  POSTGRES_HOST: "postgres-db-main"
  POSTGRES_PORT: "5432"

---

apiVersion: apps/v1
kind: Deployment
metadata:
  name: example-app
  namespace: staging
  labels:
    app: example-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: example-app
  strategy:
    type: RollingUpdate
  progressDeadlineSeconds: 300
  template:
    metadata:
      labels:
        app: example-app
    spec:
      volumes:
      - name: shared-data
        emptyDir: {}
      containers:
      - image: XXXXXXXXXXXX.dkr.ecr.eu-west-1.amazonaws.com/litslink:example-application
        name: example
        volumeMounts:
        - name: shared-data
          mountPath: /usr/src/app
        imagePullPolicy: "IfNotPresent"
        ports:
          - containerPort: 8080
        envFrom:
            - configMapRef:
                name: example-config
      - image: XXXXXXXXXXXX.dkr.ecr.eu-west-1.amazonaws.com/base-image:example-nginx
        name: example-nginx
        volumeMounts:
        - name: shared-data
          mountPath: /usr/share/nginx/html
        imagePullPolicy: "IfNotPresent"
        ports:
          - containerPort: 80
      nodeSelector:
        nodegroup: staging

---

apiVersion: v1
kind: Service
metadata:
  name: example-svc
  namespace: staging
spec:
  ports:
  - port: 80
  selector:
    app: example-app

---

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: example-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: /
spec:
  tls:
  - hosts:
    - example.artem.services
    secretName: example.artem.services-secret-tls
  rules:
  - host: example.artem.services
    http:
      paths:
      - path: /
        backend:
          serviceName: example-svc
          servicePort: 80

Читать далее "Kubernetes — Пример манифеста пода с двумя контейнерами"

MacOS — Sublime Text 3  по умолчанию

Так как часто приходится работать с файлами без расширения или с разным расширением, что не дает возможность сделать полностью по умолчанию задать через Finder.

Решение следующее, добавить в ваш шел Bash.bash_profile или ZSH.zshrc следующее:

defaults write com.apple.LaunchServices LSHandlers -array-add '{LSHandlerContentType=public.plain-text;LSHandlerRoleAll=com.sublimetext.3;}'

Sublime Text 3 по умолчанию открывал все в новых окнах, чтобы он открывал в новой вкладке, в настройки "SublimeText > Prefferences > Settings" добавить следующую строку:

"open_files_in_new_window": false

Так же настроек приложений по умолчанию можно воспользоваться RCDefaultApp.