Поиск

Найдены 19 статей по слову "devops"

Ошибка InnoDB could not find key

Пример ошибки (получил ее от Nextcloud у MariaDB, когда закончилось место):

InnoDB could not find key no 1 with name mounts_user_root_index from dict cache for table nextcloud/oc_mounts

Как исправить.

  1. Заходим в консоль mysql
mysql -uLOGIN -p DATABASE
  1. Исправляем ошибки :)
mysql> ALTER TABLE oc_mounts FORCE;

Все, перезагрузка сервиса MariaDB не потребовалось, все заработало.

devops mysql

Бекапы через Duplicity

У меня уже был установлен, если нет, то:

apt install -y duplicity

Запускать его рекомендую под root. А также добавить в cron.

Делаем бекап без шифрования.

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

duplicity --no-encryption /home/crusat/www/crusat file:///mnt/backup/incremental/

Пример вывода:

Local and Remote metadata are synchronized, no sync needed.
Last full backup date: none
No signatures found, switching to full backup.
--------------[ Backup Statistics ]--------------
StartTime 1685457148.21 (Tue May 30 17:32:28 2023)
EndTime 1685457321.37 (Tue May 30 17:35:21 2023)
ElapsedTime 173.16 (2 minutes 53.16 seconds)
SourceFiles 2598
SourceFileSize 2430153960 (2.26 GB)
NewFiles 2598
NewFileSize 2430153960 (2.26 GB)
DeletedFiles 0
ChangedFiles 0
ChangedFileSize 0 (0 bytes)
ChangedDeltaSize 0 (0 bytes)
DeltaEntries 2598
RawDeltaSize 2428822760 (2.26 GB)
TotalDestinationSizeChange 559464350 (534 MB)
Errors 0
-------------------------------------------------

После инкрементального пример вывода:

Local and Remote metadata are synchronized, no sync needed.
Last full backup date: Tue May 30 17:32:28 2023
--------------[ Backup Statistics ]--------------
StartTime 1685458987.94 (Tue May 30 18:03:07 2023)
EndTime 1685458988.72 (Tue May 30 18:03:08 2023)
ElapsedTime 0.79 (0.79 seconds)
SourceFiles 2598
SourceFileSize 2430165025 (2.26 GB)
NewFiles 1
NewFileSize 4096 (4.00 KB)
DeletedFiles 0
ChangedFiles 5
ChangedFileSize 16991003 (16.2 MB)
ChangedDeltaSize 0 (0 bytes)
DeltaEntries 6
RawDeltaSize 72816 (71.1 KB)
TotalDestinationSizeChange 18152 (17.7 KB)
Errors 0
-------------------------------------------------

Делаем полный бекап:

duplicity --no-encryption --full /home/crusat/www/crusat file:///mnt/backup/full/

При необходимости, можно исключить файлы с помощью опции --exclude.

Восстанавливаем бекап:

duplicity --no-encryption restore file:///mnt/backup/incremental/ /home/crusat/www/crusat

Восстанавливаем бекап трехдневной давности:

duplicity -t 3D --no-encryption restore file:///mnt/backup/incremental/ /home/crusat/www/crusat

Восстанавливаем конкретный файл:

duplicity --no-encryption --file-to-restore FILENAME file:///mnt/backup/incremental/ /home/crusat/www/crusat

Все работает через scp, поэтому можно делать так:

duplicity --no-encryption /home/crusat/www/crusat scp:///user@backup.ru/incremental/

Добавляем в cron для ежедневных бекапов:

crontab -e
# добавляем через любимый редактор задачу на час ночи ежедневно
0 1 * * * duplicity --no-encryption /home/crusat/www/crusat file:///mnt/backup/incremental/

Всем спасибо за внимание.

bash copypaste devops

Простое нагрузочное тестирование на Siege

Siege - простой инструмент для нагрузочного тестирования (с одного сервера). С помощью него можно увидеть среднее время ответа и уже на этапе разработки, на своей машине, проверить, не слишком ли долго отвечают какие-то ендпоинты.

Пример запроса:

siege  -d1 -r5 -c10 'https://crusat.ru'

где:

-r5 - количество запросов. В данном случае 5 запросов от каждого пользователя.
-c10 - количество одновременных пользователей. В данном случае 10 пользователей.
-d1 - задержка между запросами. Измеряется в секундах. В данном случае 1 секунда.

То есть, суммарно будет 5 * 10 = 50 запросов. Время исполнения будет не более 5 * 1 = 5 секунд (при скорости обработки запроса в 0 секунд).

Пример вывода:

Transactions:                510 hits
Availability:             100.00 %
Elapsed time:              12.75 secs
Data transferred:           5.80 MB
Response time:              0.18 secs
Transaction rate:          40.00 trans/sec
Throughput:             0.46 MB/sec
Concurrency:                7.14
Successful transactions:         510
Failed transactions:               0
Longest transaction:            1.06
Shortest transaction:           0.05
bash devops

Пример nginx + letsencrypt для docker-compose

Внесите в ваш docker-compose.yml следующие изменения и оставьте открытыми порты (80 и 443) только в сервисе nginx-proxy и добавьте VIRTUAL_HOST и LETSENCRYPT_HOST в environments в ваш сервис (или сервисы), который слушает 80 порт (можно использовать и другие порты/настройки, см. ниже):

version: '2'

services:

  nginx-proxy:
    image: jwilder/nginx-proxy
    container_name: nginx-proxy
    ports:
      - 80:80
      - 443:443
    restart: always
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - ./vhost.d:/etc/nginx/vhost.d:ro
      - ./data/certs:/etc/nginx/certs
      - ./data/html:/usr/share/nginx/html
      - ./proxy.conf:/etc/nginx/proxy.conf

  nginx-proxy-letsencrypt:
    image: jrcs/letsencrypt-nginx-proxy-companion
    restart: always
    environment:
      - DEFAULT_EMAIL=crusat@yandex.ru
      - NGINX_PROXY_CONTAINER=nginx-proxy
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /etc/acme.sh
      - ./vhost.d:/etc/nginx/vhost.d
      - ./data/certs:/etc/nginx/certs
      - ./data/html:/usr/share/nginx/html

  server:
    # ...
    environment:
      - VIRTUAL_HOST=example.ru
      - LETSENCRYPT_HOST=example.ru

  # ...

Создайте в корне файл proxy.conf:

# HTTP 1.1 support
proxy_http_version 1.1;
proxy_buffering off;
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $proxy_connection;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
proxy_set_header X-Forwarded-Ssl $proxy_x_forwarded_ssl;
proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port;

# Mitigate httpoxy attack (see README for details)
proxy_set_header Proxy "";

# additional
proxy_connect_timeout 3000;
proxy_send_timeout 3000;
proxy_read_timeout 3000;
send_timeout 3000;

Создайте файл vhost.d/default:

## Start of configuration add by letsencrypt container
location ^~ /.well-known/acme-challenge/ {
    auth_basic off;
    auth_request off;
    allow all;
    root /usr/share/nginx/html;
    try_files $uri =404;
    break;
}
## End of configuration add by letsencrypt container

client_max_body_size 200m;

Также, если необходимо несколько доменов, то можно добавить прокси по имену домена, например, vhost.d/example.ru:

## Start of configuration add by letsencrypt container
location ^~ /.well-known/acme-challenge/ {
    auth_basic off;
    auth_request off;
    allow all;
    root /usr/share/nginx/html;
    try_files $uri =404;
    break;
}
## End of configuration add by letsencrypt container

server_tokens off;
client_max_body_size 2000m;

Для дополнительной документации смотрите сюда: https://hub.docker.com/r/jwilder/nginx-proxy/

devops docker

HTTPS на localhost

Когда на локалхосте нужен https можно сделать следующее.

Выполняем команду:

openssl req -x509 -out localhost.crt -keyout localhost.key \
  -newkey rsa:2048 -nodes -sha256 \
  -subj '/CN=localhost' -extensions EXT -config <( \
   printf "[dn]\nCN=localhost\n[req]\ndistinguished_name = dn\n[EXT]\nsubjectAltName=DNS:localhost\nkeyUsage=digitalSignature\nextendedKeyUsage=serverAuth")

Копируем файлы localhost.crt и localhost.key в папку приложения и подключаем.

Также, не забывайте, что может потребоваться добавить сертификат в кейчеин (на маке просто делаем двойной клик по localhost.crt).

Также, может потребоваться перейти по ссылке на сертификат (если допустим подключается апи к другому хосту), то просто открывайте сайт по тому урлу и соглашайтесь через “Дополнительно” и “Перейти на сайт”.

Например, для nodejs код будет выглядеть примерно так (index.js):

const https = require('https');

const HTTPS_OPTIONS = Object.freeze({
    cert: fs.readFileSync('./localhost.crt'),
    key: fs.readFileSync('./localhost.key')
});

const httpsServer = https.createServer(HTTPS_OPTIONS);

Источник: https://letsencrypt.org/ru/docs/certificates-for-localhost/

devops

Docker показывает IP контейнера, а не пользователя

Это в первую очередь касается PHP проектов.

Делаем две вещи. Первое - для reverse proxy (если используется) у nginx дописываем в раздел следующее:

server {
    ...
    location / {
        ...
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        ...
    }
    ...
}

И рестартим nginx.

После этого у нас для переменной $_SERVER['HTTP_X_REAL_IP'] будет правильный IP-адрес клиента, а для $_SERVER['REMOTE_ADDR'], скорее всего, останется неправильной.

Второе, что делаем - надо прокинуть правильную переменную в fastcgi_param. Идем во внутренний nginx и исправляем конфиг:

server {
    ...
    location ~ \.php$ {
        ...
        fastcgi_param REMOTE_ADDR $http_x_real_ip;
        ...
    }
    ...
}
devops nginx php

git падает с нехваткой памяти

Когда вы видите подобное сообщение от git при пуше:

Delta compression using up to 2 threads.
warning: suboptimal pack - out of memory 
error: pack-objects died of signal 90)   
fatal: The remote end hung up unexpectedly
fatal: The remote end hung up unexpectedly
error: failed to push some refs to '...'
fatal: write error: Bad file descriptor

То можете попробовать увеличить размер доступной памяти, это может помочь. Для этого выполните команду

git config --global pack.windowMemory "32m"

и попробуйте запушить еще раз.

bash copypaste devops

Логирование POST-запросов в nginx

Для разработки периодически возникает необходимость логировать запросы для того, чтобы разобраться в проблеме. Если используете nginx, то можно настроить логирование запросов на его стороне.

Для этого надо создать новый формат лога и выставить его в виртуальном хосте. Также, рекомендую выставить client_body_buffer_size побольше, т.к., если вы превысите стандартный размер в килобайт, то вместо тела запроса будет “-“.

Форматируем лог, в убунту при стандартной установке это файл /etc/nginx/nginx.conf:

# ...

http {
    # ...
    client_body_buffer_size 100K;
    client_header_buffer_size 10k;

    log_format postdata '$http_x_forwarded_for - $remote_user [$time_local] "$request" '
                '$status $body_bytes_sent "$request_body" "$http_referer" '
                '"$http_user_agent" $request_time';
    # ...
}
# ...

И выставляем в виртуальном хосте, например /etc/nginx/sites-enabled/default:

server {
    # ...
    access_log /var/log/nginx/postdata.log postdata;
    # ...
}

Проверяем, что все написали правильно и конфигурация “ок”:

nginx -t

Перезагружаем сервер:

service nginx restart

Делаем запрос и идем смотреть лог /var/log/nginx/postdata.log.

Если у вас не создался лог, проверьте, создана ли директория, где он лежит и есть ли у nginx права на запись в этой директории на этот файл.

devops nginx

Отправка почты через mail() из php

Крайне не рекомендую использовать php-функцию mail() для отправки почты. Лучше все-таки отправлять ее через smtp с возможностью настройки из приложения всех необходимых данных.

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

<span>1.</span> Устанавливаем sendmail

apt install sendmail -y

<span>2.</span> Вносим изменения в /etc/hosts:

127.0.0.1 localhost localhost.localdomain yourdomain
...

<span>3.</span> Перезапускаем конфиг (на все вопросы отвечаем утвердительно):

sendmailconfig

<span>4.</span> Перезагружаем все:

service nginx restart
service sendmail restart
service php7.0-fpm restart

<span>5.</span> Готово, можно проверять:

<?php

echo  mail(
    "mymail@yandex.ru",
    "test message",
    "test message",
    "From:no-reply@gmail.com"
);

bash bitrix devops linux php

Глобально меняем ключи доступа и пароли от всех своих серверов с помощью Ansible

Если вам необходимо обновить ключи доступа и пароли на многих серверах (например, ушел какой-либо сотрудник у которого был доступ к каким-то серверам, либо просто в целях безопасности обновить надо, либо для CI, вариантов куча), то можно использовать для этого Ansible.

Создайте директорию public_keys/, где будете хранить ваш ключ и ключи ваших сотрудников. Добавьте туда все необходимые ключи, например:

Файл public_keys/crusat:

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDVk9yuKpN/c1+TsM3i0YW5H1Z86dVZQvAkOAxF3VZMIS48Ng6JjTOx58/kf5Z1fjNVcxNWv0uyrARstgZTokWiNfeHGYyMR+htivsJnFHiG6i1OXUdRAfNh84EXPm0LZbvzcRm9MM36nsa5cNS4dGE8ZxObW29O....

Со всеми остальными проделайте то же самое.

Теперь создадим плейбук set_access.yml (обратите внимание на обращение к ключам из public_keys - эти ключи будут добавлены, адаптируйте под себя):

---
- hosts: all 
  remote_user: root
  vars_files: ['credentials.yml']
  tasks:
  - name: Set main authorized key and remove existent
    authorized_key:
      user: root
      state: present
      key: '{{ item }}'
      exclusive: True
    with_file:
      - ./public_keys/crusat
  - name: Set up other keys
    authorized_key:
      user: root
      state: present
      key: '{{ item }}'
    with_file:
      - ./public_keys/user1
      - ./public_keys/user2
  - name: Set root password
    user:
      name: root
      state: present
      update_password: always
      password: "{{ admin_default_password }}"
      shell: /bin/bash

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

Для этого создадим файл set_access.sh:

#!/bin/bash

NEW_PASSWORD='mysuperpassword'

HASHED_PASSWORD=`python3 -c 'import crypt; print(crypt.crypt("'"$NEW_PASSWORD"'", crypt.mksalt(crypt.METHOD_SHA512)))'`

echo 'admin_default_password: '$HASHED_PASSWORD > ./credentials.yml

ansible-playbook -i inventory_hosts -l test ./set_access.yml

Здесь укажите правильный путь к инвентарю. Суть в следующем - скрипт берет пароль, хэширует его, помещает в файл credentials.yml и затем выполняет плейбук, который как раз возьмет хэшированный пароль как переменную и задаст необходимый пароль для пользователя root.

ansible bash copypaste devops