Вспомнил давно забытые преподские дела 🙂 да.
Записал начало видео курса по Кубернетес.
А что? Самоизоляция, она кого угодно достанет…
Вакансии Системный администратор Linux
В дружественной компании открыты вакансии Сисадминов Linux. Компания надежная. Работа удаленная, т.е. кандидат может проживать в любом регионе России. Работы много, кризис на работу не влияет, даже увеличил её (работы) количество.
Системный администратор Linux
Обязанности:
- Администрирование и поддержка информационных систем: микросервисы, WEB приложения.
- Участие в релизах, выполнение регламентных работ (несколько раз в месяц работы могут быть после 20:00 по Москве)
Требования:
- Уверенные знания принципов работы сетей TCP/IP (как минимум умение пользоваться базовыми программами типа tcpdump, traceroute и прочих. Понимание возможных ошибок и путей их устранения).
- Хорошие знания nginx (настройка, поиск неисправностей, мониторинг ошибок).
- Понимание работы приложений java (настройка запуска, мониторинг, умение читать java логи, понимание основных ошибок).
- Грамотная речь и письмо.
- Способность к обучению, инициативность.
- Плюсом при собеседовании являются знания:
- ansible, haproxy, docker, prometheus, elasticsearch, git, kubernetes.
- Понимание процессов DevOps.
- Базовые знания PostgreeSQL (выполнение простых SQL запросов).
Условия:
- Удаленная работа (по желанию, возможно в офисе м. Павелецкая).
- Официальное трудоустройство.
- Возможности профессионального и карьерного роста.
Системный администратор Alfresco
Обязанности:
- Администрирование и поддержка Alfresco Community Editions.
- Администрирование и поддержка информационных систем: микросервисы, WEB приложения.
Требования:
- Опыт работы с Alfresco Community Editions.
- Понимание работы приложений java (настройка запуска, мониторинг, умение читать java логи, понимание основных ошибок).
- Уверенные знания принципов работы сетей TCP/IP.
- Грамотная речь и письмо.
- Способность к обучению, инициативность.
- Плюсом при собеседовании являются знания:
- ansible, docker, prometheus, elasticsearch.
- работа с файловыми системами Linux, в том числе сетевыми и распределенными.
- знание LVM.
Условия:
- Удаленная работа (по желанию, возможно в офисе м. Павелецкая).
- Официальное трудоустройство.
- Возможности профессионального и карьерного роста.
Так же есть вакансии:
- в службу поддержки первой линии,
- задачи в области тестирования и мониторинга.
Ссылки на резюме (желательно на hh.ru) присылайте на мыло arturkryukov@krlb.ru
Elasticsearch и ошибка «failed to parse field [time] of type [date]»
В один прекрасный день, elastic может сойти с ума. Перестать принимать информацию в индекс и начать кидать в логи ошибки типа:
failed to parse field [time] of type [date]
Проблема в автоматическом распознавании содержимого полей. Особенно это касается поля, в котором содержится дата и время. Тот самый прекрасный день настал, когда наши программеры немножечко изменили формат даты. И этот формат не стал совпадать с форматом, который эластик использует по умолчанию.
Какой формат используется можно увидеть в mapping интересующего вас индекса:
GET /index-name/_mapping
Следующая засада, вы не можете на лету поменять тип поля в индексе. Только путем пересоздания индекса с нуля.
И самое противное. Если вы используете группу индексов в IndexPattern, сбойный индекс вылетит из поиска по проблемному полю.
Вобщем проблем с такими «прыгающими» типами полей будет чертовски много. Поэтому, рекомендую «гвоздями» прибивать тип поля в индексе.
Например, в индексе есть поле, содержащее дату. В Elastic такие поля могут попасть под шаблон (mapping) по умолчанию для даты и в индексе появится поле типа date. Потом программеры поменяют формат даты и поле перестает подходить под шаблон. Эластик будет считать что это поле типа text и тупо перестает добавлять информацию в индекс.
Если вы не планируете в дальнейшем использовать поле для поиска, самое простое решение привести его к типу text. В дальнейшем, смена формата даты никоим образом не повлияет на работу индекса.
Создание шаблона для индекса или группы индексов.
Посмотреть все шаблоны можно так:
GET _template
Посмотреть конкретный шаблон:
GET _template/template_name
Создать шаблон:
PUT _template/template_name
{
"order" : 0,
"index_patterns" : [
"index-name-*"
],
"settings" : {
"index" : {
"number_of_shards" : "1"
}
},
"mappings" : {
"properties": {
"time": {
"type" : "text",
"fields" : {
"keyword" : {
"ignore_above" : 256,
"type" : "keyword"
}
}
}
}
},
"aliases" : { }
}
Параметр index-patterns определяет шаблон именён индексов к которым будет применяться данный template. Т.е. если будет создан индекс с , например, именем index-name-2020.04.01, то шаблон будет к нему применен. И в дальнейшем в списке mappings вы увидите, что поле time будет иметь тип text.
Так же в этом шаблоне ограничивается количество шардов единицей. По умолчанию у вновь создаваемого шаблона значение этого параметра равно 3. Такое ограничение имеет смысл для небольших индексов. Максимальное количество шардов на сервер ограничено и при большом количестве индексов имеет смысл на один индекс давать один шард.
OpenVPN and OpenLDAP, not MD5 hash password
Собственно коронавирус, пользователи стаями потянулись на удалёнку. Пришла пора VPN серверов.
Достаточно стандартное решение OpenVPN + OpenLDAP позволяет управлять доступом пользователей к vpn серверу. Конфигурируется незамысловато, в интернет есть куча готовых советов как это делать. У меня в старой wiki была статейка как приготовить OpenVPN. Предупреждаю, статейка старинная, но еще рабочая.
Но в процессе настройки нашел забавную особенность:
Если в OpenLDAP для хеширования пароля используется не MD5, то плагин openvpn-auth-ldap будет давать ошибку.
А в случае MD5 — все работает как часы.
Попытался было заглянуть в исходники модуля. И понял, что современный С (или что они там использовали) далеко ушел от классического Керниган&Ритчи 🙂 Поэтому вот, пришлось возвращаться к MD5.
Если кто разбирается в современном С и норм владеет английским, скажите авторам, что: «Хьюстон, у нас проблемы».
З.Ы. Странно как то. Но оно заработало с разными типами хешей. И ведь ничего не трогал.
Нашел награды Деда.
На сайте «Память народа» постепенно выкладывают сканы архивных документов. Регулярно туда заходил, но данных про деда Плетнёва Ивана Сергеевича не находилось.
Сегодня повторил поиск и нашел сразу три награды.
Добавил на «Память народа» личную страницу деда.
Как верно подмечено

Hibernate, Spring и имена таблиц, полей базы данных.
Эх, давно не брал я в руки шашку. (с) Василий Иванович
Пришлось и мне встать на тропу микросервисов. Поскольку java основной язык программирования, то в качестве платформы был выбран Spring. Начинаю потихоньку копать этот фреймворк.
Досталась мне в наследство базёнка, в которой имена таблиц и полей начинаются с большой буквы. Типа: Notes, NotesIndex и т.п.
Настраиваю spring JPA, все как в примере работы с MySQL. Только в отличии от примера использую готовую таблицу. Проверку опять же:
spring.jpa.hibernate.ddl-auto=validate
Описываю сущности. Причем понимаю, что название таблиц и полей нестандартное, явно указываю имена:
@Data
@Entity
@Table(name = "Notes")
public class Notes {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="NoteIndex")
private int noteIndex;
Запускаю приложение и ловлю ошибку:
nested exception is org.hibernate.tool.schema.spi.SchemaManagementException: Schema-validation: missing table [notes]
Вот засада! Я ведь явно указал имя таблицы. Долго копался в интернетах и нашел решение: необходимо явно определить стратегию именования, иначе не реагирует оно на мои имена таблиц.
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
Kubernetes, включение RBAC на namespace
Создадим namespace artur, доступ к которому будем разрешать пользователю artur:
# kubectl create namespace artur
Как создавать пользователя было описано тут.
Создаём файл с описанием role и rolebindig — 01. yaml следующего содержания:
--- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: artur # namespace к которому применяются огранияения name: artur-role rules: - apiGroups: [""] # "" indicates the core API group resources: ["pods", "services", "replicationcontrollers"] verbs: ["create", "get", "update", "list", "delete"] - apiGroups: [""] resources: ["pods/log"] verbs: ["get", "list"] - apiGroups: [""] resources: ["pods/exec"] verbs: ["create"] - apiGroups: ["apps"] resources: ["deployments","daemonsets","replicasets","statefulsets"] verbs: ["create", "get", "update", "patch", "list", "delete", "deploy"] - apiGroups: ["autoscaling"] resources: ["horizontalpodautoscalers"] verbs: ["create", "get", "update", "list", "delete"] - apiGroups: ["batch"] resources: ["jobs","cronjobs"] verbs: ["create", "get", "update", "list", "delete"]--- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: artur-rb namespace: artur subjects: - kind: User name: artur apiGroup: rbac.authorization.k8s.io roleRef: kind: Role name: artur-role apiGroup: rbac.authorization.k8s.io
Создаем роли и биндинги в кубернетес.
# cubectl apply -f 01.yaml
Всё, что тут написано — это художественная обработка материалов доброго человека.
Kubernetes, доступ по сертификату пользователя
В принципе — это шпаргалка, что бы не забыть как все на самом деле происходит 🙂
Создание SSL ключа и сертификата пользователя
Создаём временную директорию:
# mkdir tmp # cd tmp
Генерируем SSL ключ пользователя:
# openssl genrsa -out artur.key 4096
Создаём конфигурационный файл для openssl — csr.cnf следующего содержания:
[ req ] default_bits = 2048 prompt = no default_md = sha256 distinguished_name = dn [ dn ] CN = artur O = dev [ v3_ext ] authorityKeyIdentifier=keyid,issuer:always basicConstraints=CA:FALSE keyUsage=keyEncipherment,dataEncipherment extendedKeyUsage=serverAuth,clientAuth
Генерируем запрос на сертификат:
# openssl req -config csr.cnf -new -key artur.key -nodes -out artur.csr
Формируем запрос на сертификат в формате base64 и помещаем его в переменную среды окружения:
# export BASE64_CSR=$(cat artur.csr | base64 | tr -d '\n')
Создаём yaml файл csr.yaml с запросом на подпись следующего содержания:
apiVersion: certificates.k8s.io/v1beta1
kind: CertificateSigningRequest
metadata:
name: artur_csr
spec:
groups:
- system:authenticated
request: ${BASE64_CSR}
usages:
- digital signature
- key encipherment
- server auth
- client auth
Помещаем запрос в кубернетес:
# cat csr.yaml | envsubst | kubectl apply -f -
Контролируем наличие запроса:
# kubectl get csr
Подписываем и генерируем сертификат:
# kubectl certificate approve artur_csr
Копируем во временную директорию файл ~/.kube/config и в разделе users удаляем из него строки client-certificate-data и client-key-data.
Добавляем в config строку с сертификатом клиента в формате base64:
# echo "client-certificate-data: $(kubectl get csr artur_csr -o jsonpath={.status.certificate})" >> config
В редакторе делаем правильное выравнивание строки. Также везде меняем пользователя на artur.
Добавляем в config файл ключ пользователя в формате base64:
# kubectl --kubeconfig ./config config set-credentials artur --client-key=artur.key --embed-certs=true
Смотрим получившийся конфигурационный файл:
# kubectl --kubeconfig ./config config view
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: DATA+OMITTED
server: https://192.168.0.45:6443
name: cluster.local
contexts:
- context:
cluster: cluster.local
user: artur
name: artur@cluster.local
current-context: artur@cluster.local
kind: Config
preferences: {}
users:
- name: artur
user:
client-certificate-data: REDACTED
client-key-data: REDACTED
Передаём файл config пользователю или копируем его в директорию ~/.kube пользователя.
Шпаргалка сделана по мотивам записок доброго человека.
Чудеса случаются.
«Налетай, торопись, покупай живопись!»
New Always Free Services
Oracle + халява — два несовместимых слова. Однако… мне кажется, что Оракл достаточно поздно включился в гонку облачных сервисов. Поэтому им приходится наступать на горло своей патологической жадности, что бы привлекать новых клиентов.











