Thứ Sáu, 18 tháng 3, 2022

Ansible Cheat Sheet


Vim config fast Ansible

# vim ~/.vimrc 
set ts=2 sw=2
set tabstop=2

Inventory

[redis_server]
pc1 ansible_ssh_host=192.168.122.129 install_redis=yes  redis_role=master
pc2 ansible_ssh_host=192.168.122.128 install_redis=yes  redis_role=slave
pc3 ansible_ssh_host=192.168.122.129 install_redis=yes  redis_role=slave

Roles

Khai báo roles

---
- name: Install redis
  hosts: redis
  vars:
    - ahihi: 'kaka'
  
  roles:
    - role: redis-all-in-one
      become: true

Folder and File

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/file_module.html

- name: create folder
  file:
    path: /setup
    state: directory #hoặc file
    owner: foo
    group: foo
    mode: '0755'
    
- name: delete folder
  file:
    path: /setup
    state: absent

Debug

- name: show echo
  shell: echo {{ tuanda }}
  register: kiemtra

- name: Debug kiem tra lan 1
  debug:
    var: kiemtra

- name: debug kiem tra lan 2
  debug:
    msg: XIN CHAO {{ kiemtra }}

Tags

Để gọi riêng từng nhóm tags, đỡ phải chạy task không cần thiết như make redis (bỏ). Ta gọi thẳng start redis

Variable Priority

https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#understanding-variable-precedence cái nào xuất hiện trước, sẽ được ưu tiên lấy ra đầu tiên

1. File trong yml role > inventory /etc/ansible/hosts
- option -e cao nhất (0)
- Khai báo trong thư mục roles/xxx/vars (1) sẽ có độ ưu tiên cao nhất, dù khai báo 2,3,4 đều không lấy biến đó.
- file role tổng (2) (file gọi các roles)
- file inventory /etc/ansible/hosts (3)
- file trong roles/xxx/default (4)

group_vars và host_vars (Thư mục)

Thứ tự các file sắp xếp như dưới đấy. Việc oder file nào trước nằm ở mục Variable Priority

[tuanda@master-node nfs-server-client]$ cat inventory.yml 
[nfs_server]
pc1 ansible_ssh_host=192.168.56.12
[nfs_client]
pc2 ansible_ssh_host=192.168.56.13

[tuanda@master-node nfs-server-client]$ tree
.
├── group_vars
│   ├── all.yml
│   ├── nfs_client
│   │   ├── nfs_client.yml
│   │   └── nfs_server.yml
│   └── nfs_server
├── host_vars
│   ├── pc1.yml
│   └── pc2.yml
├── inventory.yml
├── nfs.yml
└── roles

Copy

- name: Upload package require
  copy:
    src: "{{ item }}.rpm"
    dest: /setup/
  loop: "{{ package_names }}"

Local Copy

Lưu file từ stdout > Ansible master

- name: "Storing Token"
  local_action: copy content={{ x.stdout }} dest=/tmp/token

Template


Unarchive

- name: Extract foo.tgz into /var/lib/foo
  unarchive:
    src: /var/lib/foo.tgz
    dest: /var/lib/foo/

Lookup get file

- name: Set authorized key took from file
  authorized_key:
    user: charlie
    state: present
    key: "{{ lookup('file', '/home/charlie/.ssh/id_rsa.pub') }}"

Loop

Ngoài loop theo item liệt kê. ta còn có thể loop theo variable theo loop.

loop:
  - {{ list_port }}

Verify inventory

Để kiểm tra Ansible đang load variable từ những file nào, giá trị latest ra sao, ta có thể chạy

ansible-inventory -i host.yaml --list    (dạng json)ansible-inventory -i host.yaml --list -y (dạng yaml)

Handler:

- name: "restart redis 1"
  service:
    name: "{{ redis_service_name }}"
    state: restarted
 Sau đó gọi bằng notify: restart redis 1

Create user if not exist

- name: check if redis user exists (ignore errors)
  command: id {{ redis_user }}
  ignore_errors: yes
  changed_when: false
  register: user_exists

- name: add redis group
  group:
    name: "{{ redis_group }}"
    state: present
  when: user_exists is failed

- name: add redis user
  user:
    name: "{{ redis_user }}"
    group: "{{ redis_group }}"
    comment: "Redis"
    home: "{{ redis_install_dir }}"
    shell: /bin/false
    system: yes
  when: user_exists is failed

when

VD1: Compare variable string

[redis_server] < Ta đặt inventory variable như sau:
192.168.122.129 install_redis=yes  redis_role=master
... 
when:
    - redis_role  == 'master'

Ví dụ 2: When with variable bool

Ta đặt default var là redis_tarball: false
  when: not redis_tarball
  when: redis_tarball
Nếu là false thì
nếu là string hoặc interger thì: 

For jinja

Link kiểm tra Jinja https://cryptic-cliffs-32040.herokuapp.com/ File default:

redis_save:
  - 900 1
  - 300 10
  - 60 10000

File template

{% for save in redis_save -%}
save {{ save }}
{% endfor -%}

IF ijnja

Trong file default mặc định để false. Nếu thay đổi thì xóa false đi và thay bằng string

redis_bind: false

Trong file Template

{% if redis_bind -%}
bind {{ redis_bind }}
{% else %}
bind 127.0.0.1
{% endif -%}
>>>> Hoặc, để bỏ dòng bind nếu false <<<<<
{% if redis_bind -%}
bind {{ redis_bind }}
{% endif -%}

Giải thích: Nếu false thì sẽ không có trong file config, nếu không false thì sẽ là string và kết quả là: requirepass matkhau

Ansible Vault

Phần 1: Tạo và chạy Vault (mã hóa all)

ansible-vault create test1.yaml
---
- hosts: api
  become: true
        
  tasks:
    - name: echo text
      shell: echo XINCHAO

ansible-vault edit test1.yaml
ansible-vault view test1.yaml
ansible-playbook test1.yaml --ask-vault-pass

Phần 2: Chèn vault vào variable

ansible-vault encrypt_string --vault-id @prompt thisismysupersecretstring
---
- hosts: api
  become: true

  vars:
    secret: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          66666435303938323065643534376535633535353766323062633566313038313839343038336237
          3966616433326432643365623136383332313733646333390a333762663236393636613232663762
          33313861656264313061363265653031366538373662336132626465613839313335613862343464
          6436303837643761630a666532623532616431303632613466646661326566326332306264323236
          61383331333833333530373934356333653962396661336336653034306339306333        
  tasks:
    - name: echo text
      shell: echo {{ secret }}

Sau đó ta chạy
ansible-playbook test1_encrypt.yaml --ask-vauld-pass
ansible-playbook test1_encrypt.yaml --vault-password-file=pass.txt

Chủ Nhật, 13 tháng 3, 2022

Phần 1: K8s regisrty với basic authen và self-certificate

 Bước 1. Chỉ định hosts:

echo 192.168.88.12 registry.tuanda.vn >> /etc/hosts

Bước 2: Import basic-auth và ssl vào configmap

# mkdir /opt/certs /opt/registry
# cd /opt
# openssl req -x509 -out ca.crt -keyout ca.key -days 1825 \
  -newkey rsa:2048 -nodes -sha256 \
  -subj '/CN=registry.tuanda.vn' -extensions EXT -config <( \
   printf "[dn]\nCN=registry.tuanda.vn\n[req]\ndistinguished_name = dn\n[EXT]\nsubjectAltName=DNS:registry.tuanda.vn\nkeyUsage=digitalSignature\nextendedKeyUsage=serverAuth")

# cd /opt/certs/
# kubectl create configmap registry-cert --from-file=ca.crt --from-file=ca.key
# yum install httpd-tools -y ; htpasswd -Bbn tuanda 123 > htpasswd
# kubectl create configmap registry-basic-auth --from-file=htpasswd
# kubectl get configmaps 

Bước 3: Tạo deployment và service NodePort

apiVersion: apps/v1
kind: Deployment
metadata:
  name: private-repository-k8s
  labels:
    app: private-repository-k8s
spec:
  replicas: 1
  selector:
    matchLabels:
      app: private-repository-k8s
  template:
    metadata:
      labels:
        app: private-repository-k8s
    spec:
      volumes:
      - name: certs-vol
        configMap:
          name: registry-cert
      - name: auth-vol
        configMap:
          name: registry-basic-auth
      - name: registry-vol
        hostPath:
          path: /opt/registry
          type: Directory

      containers:
        - image: registry:2
          name: private-repository-k8s
          imagePullPolicy: IfNotPresent
          env:
          - name: REGISTRY_AUTH
            value: htpasswd
          - name: REGISTRY_AUTH_HTPASSWD_PATH
            value: "/auth/htpasswd"
          - name: REGISTRY_AUTH_HTPASSWD_REALM
            value: Registry Realm
          - name: REGISTRY_HTTP_TLS_CERTIFICATE
            value: "/certs/ca.crt"
          - name: REGISTRY_HTTP_TLS_KEY
            value: "/certs/ca.key"
          ports:
            - containerPort: 5000
          volumeMounts:
          - name: certs-vol
            mountPath: /certs
          - name: registry-vol
            mountPath: /var/lib/registry
          - name: auth-vol
            mountPath: /auth
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: private-repository-k8s
  name: private-repository-k8s
spec:
  ports:
  - port: 5000
    nodePort: 31320
    protocol: TCP
    targetPort: 5000
  selector:
    app: private-repository-k8s
  type: NodePort

Bước 4: Trust CA

sudo cp -rp /opt/certs/ca.crt  /etc/pki/ca-trust/source/anchors/
sudo update-ca-trust
sudo service docker restart

Bước 5: Đẩy cert vào tất cả các node docker, để permit self-certificate gọi pull. (all node)

mkdir -p /etc/docker/certs.d/registry.tuanda.vn:31320
cp -rp /opt/certs/ca.crt /etc/docker/certs.d/registry.tuanda.vn\:31320/

Bước 6: docker login đẩy config registry client sang các node:

# curl -v --user tuanda:123 https://registry.tuanda.vn:31320/v2/
# docker login registry.tuanda.vn:31320 -u tuanda -p 123
cat ~/.docker/config.json 
{
	"auths": {
		"registry.tuanda.vn:31320": {
			"auth": "dHVhbmRhOjEyMw=="
		}
	}
}
mkdir -p /home/tuanda/.docker ;  chown -R tuanda.tuanda /home/tuanda/.docker
Ta copy file config.json ở trên sang các worker node trong cluster. (/home/tuanda/.docker/config.json)

Bước 6: đẩy image lên registry:

# docker pull nginx:alpine
# docker tag nginx:alpine registry.tuanda.vn:31320/nginx:alpine
# docker push registry.tuanda.vn:31320/nginx:alpine

Thứ Tư, 9 tháng 3, 2022

Phần 7: Redis Sentinel sử dụng ACL

 

Phần 7: Redis Sentinel sử dụng ACL

Seri Redis của chúng ta gồm những phần sau:

Phần 1: Cài đặt redis cơ bản + Turning redis.
Phần 2: Lệnh quản trị redis cơ bản
Phần 3: Bảo mật cho redis. (redis security)
Phần 4: Access List Redis (tính năng mới từ bản 6)
Phần 5: Các mô hình Redis replication, Ưu và nhược điểm
Phần 6: Redis Master-Salve sử dụng ACL
Phần 7: Redis Sentinel sử dụng ACL
Phần 8: Cài đặt Redis Cluster
Phần 9: Di chuyển data từ redis đơn sang cluster và ngược lại.
Phần 10: Data type trong Redis, một vài ví dụ sử dụng (String/hash/sort/list/queue/pub-sub....).
Phần 11: Một số lỗi thường gặp khi quản trị hệ thống Redis.
Phần 12: Continue...

Phần 7: Redis Sentinel sử dụng ACL

Mô hình: (nên ít nhất là có 3 node sentinel, để tránh hiện tượng bình bầu split-brain, còn M-S có thể là 2 hoặc 3 tùy ý)



192.168.88.12: Master 192.168.88.13: Slave 192.168.88.14: Slave 192.168.88.12: Sentinel 192.168.88.13: Sentinel 192.168.88.14: Sentinel

Bước 1: Bật ACL Sentinel

(Thực hiện trên cả Master và Slave, vì sau này có thể slave được promote thành Master)
# redis-cli -p 6379 --user default --pass matkhau_default
> ACL SETUSER sentinel_user on >matkhau_sentinel allchannels +multi +slaveof +ping +exec +subscribe +config|rewrite +role +publish +info +client|setname +client|kill +script|kill
> CONFIG REWRITE

Bước 2: chuẩn bị config Sentinel trên cả 3 node M-S-S

# vi /opt/redis/conf/sentinel.conf
port 26379
bind 0.0.0.0
daemonize yes
pidfile "/var/run/redis_26379.pid"
logfile "/opt/redis/log/sentinel.log"
dir "/tmp"
sentinel monitor mymaster 192.168.88.12 6379 2

sentinel auth-user mymaster sentinel_user
sentinel auth-pass mymaster matkhau_sentinel

sentinel down-after-milliseconds mymaster 3000

sentinel failover-timeout mymaster 10000
sentinel deny-scripts-reconfig yes

Bước 3: Chuẩn bị init.d sentinel hoặc systemd

adduser redis --no-create-home
touch /etc/init.d/redis_sentinel
chmod +x /etc/init.d/redis_sentinel
chmod 700 /etc/init.d/redis_sentinel
chown redis.redis /etc/init.d/redis_sentinel

Thêm file init.d
# vim /etc/init.d/redis_sentinel 
#!/bin/sh
#Configurations injected by install_server below....

EXEC=/usr/local/bin/redis-sentinel
CLIEXEC=/usr/local/bin/redis-cli
REDISPORT="26379"
CLIEXEC="/usr/local/bin/redis-cli -p ${REDISPORT}"
PIDFILE=/var/run/redis_26379.pid
CONF="/opt/redis/conf/sentinel.conf"
###############
# SysV Init Information
# chkconfig: - 58 74
# description: redis_6379 is the redis daemon.
### BEGIN INIT INFO
# Provides: redis_6379
# Required-Start: $network $local_fs $remote_fs
# Required-Stop: $network $local_fs $remote_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Should-Start: $syslog $named
# Should-Stop: $syslog $named
# Short-Description: start and stop redis_6379
# Description: Redis daemon
### END INIT INFO


case "$1" in
    start)
        if [ -f $PIDFILE ]
        then
            echo "$PIDFILE exists, process is already running or crashed"
        else
            echo "Starting Redis server..."
            $EXEC $CONF
        fi
        ;;
    stop)
        if [ ! -f $PIDFILE ]
        then
            echo "$PIDFILE does not exist, process is not running"
        else
            PID=$(cat $PIDFILE)
            echo "Stopping ..."
            $CLIEXEC -p $REDISPORT shutdown
            while [ -x /proc/${PID} ]
            do
                echo "Waiting for Redis to shutdown ..."
                sleep 1
            done
            echo "Redis stopped"
        fi
        ;;
    status)
        PID=$(cat $PIDFILE)
        if [ ! -x /proc/${PID} ]
        then
            echo 'Redis is not running'
        else
            echo "Redis is running ($PID)"
        fi
        ;;
    restart)
        $0 stop
        $0 start
        ;;
    *)
        echo "Please use start, stop, restart or status as first argument"
        ;;
esac

Thực hiện bật sentinel lên
# /etc/init.d/redis_sentinel start

Bước 4: Kiểm tra hoạt động của sentinel

[root@master-node conf]# redis-cli -p 26379 info | tail
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_tilt_since_seconds:-1
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.88.12:6379,slaves=2,sentinels=3

Kiểm tra failover sentinel (đổi master-slave cho node khác)

[root@master-node conf]# redis-cli -p 26379
127.0.0.1:26379> SENTINEL FAILOVER mymaster

Thực hiện lệnh trên cả 3 node. thấy Master và Slave đã đổi 
[root@master-node conf]# redis-cli -p 6379 --user default --pass matkhau_default  info | grep role

> Mô hình mới ta nhận được:
192.168.88.12: Slave
192.168.88.13: Master
192.168.88.14: Slave

Bonus: Cài đặt HA-Proxy tự động phát hiện master.

Bài toán: Client gặp khó khăn khi Write vào node Master trong trường hợp: Master-Slave được đổi vị trí cho nhau
Khắc phục: Sử dụng HA-Proxy để đẩy luồng write chỉ vào node Master
Link: https://vnsys.wordpress.com/2019/01/16/ha-redis-sentinel-su-dung-haproxy/
(cảm ơn tác giả bài viết)

Nguồn: https://redis.io/topics/acl

https://redis.io/topics/replication

Nginx mTLS

  A. Nginx as SERVER with mTLS Trong  hệ thống nội bộ, ca certificate thường dùng chung cả cho server và client. Nhưng nếu bảo mật hơn, có t...