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

Ứng cứu khi chown -R user1:user1 /etc

1. Bài toán Gõ nhầm: chown -R user1:user1 /etc 2. Giải: Cách 1: Tìm bản backup /etc cũ (tỉ lệ phục hồi gần như ~100%) Cách 2: Tìm tạm 1 thư ...