2022-06-09
Był sobie użytkownik. Ten użytkownik łączył się do swojej bazy danych w PostgreSQL korzystając z pgBouncera. Tyle dobrego mówi się o zarządzaniu połączeniami przez pgBouncera, że hohoho, więc użytkownik robił dobrze, że robił tak jak robił.
Pojawił się jednak problem… czasami ni z tego ni z owego pojawiał się komunikat mówiący o tym, że zapytanie wykonywane na serwerze zostało anulowane z powodu przekroczenia statement_timeout. Nie byłoby w tym nic dziwnego, gdyby nie to, że użytkownik przysięgał, że nie ustawiał u siebie statement_timout. Kto by mu tam wierzył!?
|
ERROR: canceling statement due to statement timeout |
Czasami z kolei, użytkownik narzekał, że zmienił mu się parametr search_path. Ten parametr pozwala ustalić jakie schematy mają być przeszukiwane, jeśli użytkownik napisze zapytanie do tabeli, nie podając jawnie, w jakim schemacie ta tabela się znajduje. Dlatego użytkownik od czasu do czasu dostawał błąd „nie ma takiej tabeli” i się strasznie denerwował. Oczywiście przysięgał, że sam tego parameteru nigdy nie zmieniał, ale …. kto by mu tam wierzył!?
Na dodatek, podobno, jeśli użytkownik łączył się bezpośrednio do serwera, a nie przez pgBouncer, to problemu nie było. Hmmm ciekawe, co?
O co chodzi?
PgBouncer może pracować w różnych trybach zarządzania połączeniami (connection pooling). Dwa najpopularniejsze to SESSION i TRANSACTION.
W SESSION, użytkownik otwiera połączenie do pgBouncer, a pgBouncer łączy się do PostgreSQL. Połączenie jest otwarte tak długo, jak długo trwa sesja użytkownika, co daje mniejsze oszczędności zasobów po stronie PostgreSQL. Za to, kiedy połączenie się kończy, to jest wykonywany reset ustawień takiej sesji. Wszystkie jej opcje jak np. wspomniany statement_timeout czy search_path wracają do pierwotnych ustawień. Odpowiada za to parametr pgBouncera o nazwie server_reset_query. Domyślna jego wartość to DISCARD_ALL i ta nazwa właściwie mówi wszystko sama za siebie. Wprawdzie otwarte sesje pozostaną otwarte dość długo, ale jak już zostaną zwolnione, to pgBouncer nie musi ich na nowo budować, więc jednak jakaś oszczędność zasobów jest.
W TRANSACTION, użytkownik otwiera połączenie do pgBouncer, a pgBouncer łączy się do PostgreSQL. Połączenie jest otwarte między pgBouncerem a PostgreSQLem dłużej, ale użytkownik dostaje je do dyspozycji tylko na czas działania jego transakcji. Transakcje powinny być krótkie, więc jedno połączenie pomiędzy PostgreSQL, a pgBouncerem może być wykorzystywane wiele razy. Niestety, podczas przekazywania połączeń między użytkownikami, nie jest odświeżane środowisko sesji, czyli „dziedziczy się” ustawnienia takie jak statement_timeout, czy search_path .
No i wiesz już pewnie jakie ustawienie miał mój nieszczęsny użytkownik? Tak – TRANSACTION. Opcje ustawione w jednej sesji, zaczynały działać w innej i stąd cały problem, Na nieco zmodyfikowanych ustawieniach pgBouncera (tylko 1 połączenie per 1 użytkownik per 1 baza danych w modelu TRANSACTION wyglądało to mniej więcej tak: Czytaj dalej »
2022-06-05
Ponieważ na serwerze występowały pewne problemy z pracą sterownika bazy danych, trzeba było sprawdzić jaka wersja biblioteki libpq-dev jest zainstalowana. Oto kilka metod:
apt-cache
|
apt-cache policy libpq-dev libpq-dev: Installed: 12.11-0ubuntu0.20.04.1 Candidate: 12.11-0ubuntu0.20.04.1 Version table: *** 12.11-0ubuntu0.20.04.1 500 500 http://azure.archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages 500 http://security.ubuntu.com/ubuntu focal-security/main amd64 Packages 100 /var/lib/dpkg/status 12.2-4 500 500 http://azure.archive.ubuntu.com/ubuntu focal/main amd64 Packages |
apt list
|
apt list -a libpq-dev Listing... Done libpq-dev/focal-updates,focal-security,now 12.11-0ubuntu0.20.04.1 amd64 [installed] libpq-dev/focal 12.2-4 amd64 |
aptitude
|
aptitude versions libpq-dev p 12.2-4 focal 500 i 12.11-0ubuntu0.20.04.1 focal-security,focal-updates 500 |
ldd
Dodatkowo, jeśli trzeba przeprowadzić niewielką „reverse-engineering” i odpowiedzieć na pytanie, jaki inne biblioteki zostały wykorzystane podczas kompilacji tej jednej biblioteki można posłużyć się poleceniem ldd:
|
ldd ./_psycopg.cpython-38-x86_64-linux-gnu.so linux-vdso.so.1 (0x00007fff09ce7000) libpq.so.5 => /lib/x86_64-linux-gnu/libpq.so.5 (0x00007f71f6dcc000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f71f6da9000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f71f6bb7000) libssl.so.1.1 => /lib/x86_64-linux-gnu/libssl.so.1.1 (0x00007f71f6b24000) [...] |
pg_config
A jeśli mowa jest konkretnie o bibliotece dla PostgreSQL, to można też wykorzystać polecenie pgconfig –version
|
ls /usr/bin/pg_con* /usr/bin/pg_config /usr/bin/pg_config.libpq-dev /usr/bin/pg_conftool /usr/bin/pg_config.libpq-dev --version PostgreSQL 12.11 (Ubuntu 12.11-0ubuntu0.20.04.1) |
Python
I na zakończenie jeszcze metoda z Pythona. Jeśli korzystasz z modułu psycopg2, to odwołując się do
|
psycopg2.__libpq_version__ |
możesz wyświetlić numer wersji libpq, z jaką został skompilowany moduł psycopg2
The psycopg2 module content — Psycopg 2.9.3 documentation
2022-05-24
Bezpieczeństwo swoją drogą a admini swoją. Nie no, bez przesady. Jeśli masz serwer ćwiczeniowy, na którym chcesz zminimalizować podawanie hasła, to przełączenie sudo w tryb bez hasła jest całkiem sensowne.
Żeby wyłączyć konieczność podawania hasła w sudo uruchom (ostatni raz podając hasło) polecenie
visudo to specjalny edytor do pliku sudoers. Plik jest ważny i byłoby szkoda, gdyby się uszkodził poprzez modyfikację przez kilku użytkowników na raz. Następnie na samym końcu dodaj coś w tym stylu:
|
myuser ALL=(ALL) NOPASSWD:ALL |
To istotne, żeby ta linijka była na końcu, bo w dokumentacji pliku sudoers (sudoers(5): default sudo security policy module – Linux man page (die.net)) czytamy:
When multiple entries match for a user, they are applied in order. Where there are multiple matches, the last match is used (which is not necessarily the most specific match).
I gotowe. Od tej pory użytkownik myuser nie będzie pytany o hasło podczas pracy z sudo!
2022-05-19
Modyfikacja ustawień maszyny wirtualnej w chmurze to czysta przyjemność. Wszystko dzieje się samo, wystarczy tylko wyklikać nowe zasoby i już. Czy jednak aby na pewno? Załóżmy, że na AWS chcę dodać do instancji EC2 z Linuxem dodatkowy zasób dyskowy.
Zaczyna się przyjemnie od dodania nowego wolumenu EBS w EC2 >> Volumes >> Create Volume
Najważniejsze parametry, to oprócz typu i rozmiaru, również region, w kórym ten dysk jest utworzony. Dysk da się podłączyć tylko do maszyn, które są w tym samym regionie.
Po utworzeniu wolumenu można wejść do jego właściwości i z menu Action wybrać Attach:
W formularzu podajemy, dla jakiej instancji ten wolumen ma być dostępny. Można też skonfigurować nazwę urządzenia dyskowego:
Tutaj utworzony wolumen zostanie podłączony do Linuxa poprzez urządzenie /dev/sdg
Teraz pora na zabawę po stronie systemu operacyjnego. Najpierw wylistujmy wolumeny. Jak widać w wyniku tej komendy, nowe urządzenie xvdg pojawiło się na liście:
|
ubuntu:~$ lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS loop0 7:0 0 25.1M 1 loop /snap/amazon-ssm-agent/5656 loop1 7:1 0 55.5M 1 loop /snap/core18/2409 loop2 7:2 0 61.9M 1 loop /snap/core20/1518 loop3 7:3 0 79.9M 1 loop /snap/lxd/22923 loop4 7:4 0 47M 1 loop /snap/snapd/16010 xvda 202:0 0 8G 0 disk ├─xvda1 202:1 0 7.9G 0 part / ├─xvda14 202:14 0 4M 0 part └─xvda15 202:15 0 106M 0 part /boot/efi xvdf 202:80 0 1G 0 disk /newvolume xvdg 202:96 0 1G 0 disk |
Operacje na dyskach niestety należą do tych bardziej krytycznych, bo łatwo zamazać istniejące dane przez przypadek. Dlatego warto zawsze sprawdzać, czy dysk jest rzeczywiście pusty. Można się w tym celu posłużyć poleceniem file. W zaprezentowanym poniżej wyniku widać, że dysk xvdg jest pusty, ale dysk xvdf ma już istniejący file system:
|
ubuntu:~$ sudo file -s /dev/xvdg /dev/xvdg: data ubuntu:~$ sudo file -s /dev/xvdf /dev/xvdf: Linux rev 1.0 ext4 filesystem data, UUID=1865b1e2-0734-47f6-8ed9-9492bab0348a (needs journal recovery) (extents) (64bit) (large files) (huge files) |
Mając pewność, że to TEN dysk, można na nim utworzyć system plików:
|
ubuntu:~$ sudo mkfs -t ext4 /dev/xvdg mke2fs 1.46.5 (30-Dec-2021) Creating filesystem with 262144 4k blocks and 65536 inodes Filesystem UUID: 12e55613-5f1a-4ca1-9316-e8541fd6a48e Superblock backups stored on blocks: 32768, 98304, 163840, 229376 Allocating group tables: done Writing inode tables: done Creating journal (8192 blocks): done Writing superblocks and filesystem accounting information: done |
Teraz pozostaje zmontować nowy dysk. Zaczynamy od utworzenia nowego katalogu, a następnie ręcznie montujemy system plików z nowego wolumenu. Poleceniem df można sprawdzić, że montowanie powiodło się:
|
ubuntu:~$ sudo mkdir /vol_g ubuntu:~$ sudo mount /dev/xvdg /vol_g/ ubuntu:~$ df -h Filesystem Size Used Avail Use% Mounted on /dev/root 7.6G 2.2G 5.5G 29% / tmpfs 484M 0 484M 0% /dev/shm tmpfs 194M 880K 193M 1% /run tmpfs 5.0M 0 5.0M 0% /run/lock /dev/xvdf 974M 24K 907M 1% /newvolume /dev/xvda15 105M 5.3M 100M 5% /boot/efi tmpfs 97M 4.0K 97M 1% /run/user/1000 /dev/xvdg 974M 24K 907M 1% /vol_g |
Jeśli system plików miałby się montować każdorazowo przy uruchomieniu Linuxa pozostanie jeszcze modyfikacja pliku /etc/fstab. Należy w nim dodać linijkę podobną do ostatniej poniżej:
|
LABEL=cloudimg-rootfs / ext4 discard,errors=remount-ro 0 1 LABEL=UEFI /boot/efi vfat umask=0077 0 1 /dev/xvdf /newvolume ext4 defaults,nofail 0 0 /dev/xvdg /vol_g ext4 defaults,nofail 0 0 |
Żeby przetestować tą konfigurację można teraz odmontować system plików i zmontować go ponownie poleceniem mount -a
|
ubuntu:~$ sudo umount /vol_g ubuntu:~$ sudo mount -a |
Ponowne uruchomienie df pozwoli sprawdzić, że system plików jest dostępny:
|
ubuntu:~$ df -h Filesystem Size Used Avail Use% Mounted on /dev/root 7.6G 2.2G 5.5G 29% / tmpfs 484M 0 484M 0% /dev/shm tmpfs 194M 880K 193M 1% /run tmpfs 5.0M 0 5.0M 0% /run/lock /dev/xvdf 974M 24K 907M 1% /newvolume /dev/xvda15 105M 5.3M 100M 5% /boot/efi tmpfs 97M 4.0K 97M 1% /run/user/1000 /dev/xvdg 974M 24K 907M 1% /vol_g |
2022-05-10
Chyba każdy dostępny obecnie produkt serwerowy posiada bogate możliwości konfiguracji. Część z opcji dotyczy stabilności, część wydajności, sposobu wykonywania usługi, ale duża część jest pośrednio lub bezpośrednio związana z bezpieczeństwem. Dlatego chyba każdy administrator musi sobie czasami zadać pytanie: jak mam skonfigurować mój system, żeby było bezpiecznie.
CIS (Center for Internet Security) publikuje dla wielu produktów podręczniki konfiguracji systemów, tak żeby było bezpiecznie. Np. dla PostgreSQL mamy tam kilka PDFów, każdy poświęcony innej wersji. Każda z opcji jest tam opisana:
- Jakich systemów dotyczy, bo część ustawień może być specyficzna np. tylko dla Linuxa lub Windows (Profile Applicability)
- Czego dana opcja dotyczy (Description)
- Dlaczego należy na dane ustawienie zwrócić uwagę (Rationale)
- Co się stanie, jeżeli serwer będzie niepoprawnie skonfigurowany (Impact)
- Jak sprawdzić wartość danej opcji (Audit). I w tym miejscu zazwyczaj znajdziesz polecenie, które wyświetli skonfigurowaną wartość, dzięki czemu można myśleć o budowaniu własnych mechanizmów automatyzujących sprawdzanie konfiguracji serwerów
- Jak naprawić problem (Remediation) z komendą, którą należałoby uruchomić aby zmienić ustawienie do rekomendowanej wartości
- Link do strony ze szczegółowym opisem konfiguracji (References)
- Ewentualne inne ifnoramcaje, jak np. zależności od wersji oprogramowania (Additional Information)
- Referencja do zaleceń CIS, które uzasadniają, dlaczego dana opcja została ujęta na liście (CIS Controls)
Oficjalna strona CIS to CIS Center for Internet Security (cisecurity.org)
Dokumenty opisujące konfigurację można pobrać za darmo po rejestracji.
Jeśli nie chcesz się rejestrować… poszukaj czegoś w tym stylu:
CIS postgresql filetype:pdf
U mnie znalazł się np. ten link: Index of /Security/CIS/ (bobylive.com)
2022-04-29
Ta metoda zadziała, jeśli np. chcesz systematycznie sprawdzać dostępność wybranej usługi w różnych regionach. Można też wykorzystywać API do tworzenia obiektów, ale akurat w tym przypadku, powiedziałbym że są inne wygodniejsze metody.
- Trzeba mieć utworzone konto, dobrym wyborem jest service principal. Powinno wystarczyć polecenie w postaci
|
<span class="hljs-keyword">az ad sp create-for-rbac </span><span class="hljs-parameter">--scopes</span> /subscriptions/mySubscriptionID |
W zwróconym wyniku można odnaleźć: clientId, clientSecret, Będą one potrzebne w kolejnych krokach. Proces tworzenia service principal jest opisany dokładniej tutaj: Create an Azure service principal – Azure CLI | Microsoft Docs
- Trzeba uzyskać tzw. Authorization Bareer. Można to zrobić dowolnym narzędziem do pracy z web service. Tu korzystam z curl, ale postman jest też ok. Zamaksowany identyfikator w adresie url, to tenantId:
|
curl -d 'grant_type=client_credentials&client_id=6*****6&client_secret=y******6& resource=https://management.azure.com' https://login.microsoftonline.com/6*****a/oauth2/token |
- Ta czynność odpowiada logowaniu do Azure. W odpowiedzi zostanie zwrócony dluuugi klucz, który należy wykorzystywać w kolejnych zapytaniach API wysylanych do Azure:
|
curl -X GET -H "Authorization: Bearer e*****A" https://management.azure.com/subscriptions/8*****9//providers/Microsoft.DBForPostgreSql?api-version=2020-06-01 > availability.json |
Tym razem w URL pojawia się już adres wskazujący na usługę, o której chcemy się dowiedzieć pownych rzeczy. Tutaj tą usługą jest baza danych PostgreSQL
Z dużym prawdopodobieństwem pobrany plik JSON nie będzie miał ładnego formatu, ale można nad tym popracować:
|
cat availability.json | python3 -m json.tool > availability-format.json |
A jesli np. chesz dowiedzieć się w którym regionie, jakie availability grupy są dostępne to możesz to zrobić tak:
|
import json f = open('availability-format.json', 'r') data = json.load(f) l1 = data['resourceTypes'] fs = [i for i in l1 if i["resourceType"] == "flexibleServers"] f0 = fs[0] zm = f0['zoneMappings'] loczone = [ [m['location'], m['zones']] for m in zm] for i in loczone: print(f'{i[0]} : {i[1]}') |
Linki:
Azure REST API reference documentation | Microsoft Docs
Operations – List – REST API (Azure PostgreSQL) | Microsoft Docs
Need Rest API to get the availability zones information on the basis of Object selected in a particular region · Issue #3594 · Azure/azure-rest-api-specs (github.com)
Test a REST API with curl | Baeldung
Access Azure API with a bearer token for impersonation – Sander van de Velde (wordpress.com)
Calling Azure REST API via curl. A straightforward post to invoke Azure… | by Davide Mauri | Medium
Check Name Availability – Execute – REST API (Azure PostgreSQL) | Microsoft Docs
2022-04-22
Hmmm, jaki dziwny błąd! W tłumaczeniu przy pomocy translatora dostaję: „nie można stworzyć zajezdni komunikacji międzyprocesowej„. Brawo Cisco! Na pewno każdy, kto przeczyta ten komunikat będzie wiedział o co chodzi.
Na szczęście istnieją na świecie ludzie, którzy potrafią wytłumaczyć, co należy zrobić, żeby zajezdnia komunikacji międzyprocesowej zaczęła działać: Why do I get a VPN client „unable to create the interprocess communication depot” error? (force.com)
Jeśli na swoim komputerze udostępniasz połączenie sieciowe (np. sieć lokalna może wykorzystywać Twoje połączenie internetowe, albo np. sieć wirtualna Hyper-V może łączyć się z internetem), to podobno ten komunikat jest typowy. Co zrobić?
- Odszukaj w panelu sterowania „Network Sharing Center (Centrum sieci i udostępniania)”
- Wybierz połączenie, które udostępnia sieć i przejdź do właściwości
- Na karcie Sharing/Udostępnianie odznacz opcję [x] Allow other network users to connect throug this computer’s Internet connection

Co ciekawe, po instalacji, kiedy zajezdnia komunikacji międzyprocesowej już działa, można spowrotem włączyć udostępnianie sieci i wygląda na to, że procesy mogą mimo wszystko nadal wjeżdżać do zajezdni 🙂