devops工具-Ansible進階playbook&roles

来源:https://www.cnblogs.com/wdliu/archive/2019/03/25/10592397.html
-Advertisement-
Play Games

一、playbook介紹 playbook 是 Ansible 管理配置、部署應用的核心所在,一個playbook由有多“play組成”,而一個play實際就是一個task,每個task是由多個ansible基本模塊構成,這樣我們可以用 playbook 來描述想在遠程主機執行的一些列操作,包括安裝 ...


一、playbook介紹

    playbook 是 Ansible 管理配置、部署應用的核心所在,一個playbook由有多“play組成”,而一個play實際就是一個task,每個task是由多個ansible基本模塊構成,這樣我們可以用 playbook 來描述想在遠程主機執行的一些列操作,包括安裝部署、配置管理、任務處理等等。     playbook是通過yaml格式來定義的,支持同步和非同步方式來運行,運行順序是從上到下運行每個我們定義的task,從而實現各種複雜任務。關於yaml語法可以參考這裡。 

二、核心元素

一個playbook中比較核心的組成由以下幾部分組成:
  • Hosts和User:主機列表和用戶,定義一個playbook操作的遠程主機以及登錄的用戶
  • Tasks:tasks代表任務集,定義遠程主機運行的任務列表,
  • Variables:變數,可以在playbook中傳遞變數
  • Templates:模版,復用配置文件,jinja2模版引擎
  • Handlers和Notify:觸發器,用於在task任務結束後,可以觸發其他操作 

hosts和users

  hosts代表是playbook中的主機列表,可以是主機組、單獨主機、多個主機(中間以冒號分隔開)、還可以使用通配符,users代表登錄目標主機的用戶,使用remote_user指定,當需要使用sudo進行操作時候,需要制定become參數。
---
- hosts: test       #指定主機組
  remote_user: root #指定ssh登錄的用戶
  tasks:           
    - name: test server
      ping:

使用sudo切換

---
- hosts: test
  remote_user: root
  become: yes             #become參數在2.6版本用於指定sudo
  become_user: admin       #sudo的用戶
  tasks:
    - name: test server
      ping:

tasks

  Tasks是playbook中核心組成成分部分,用於在定義遠程主機執行的一系列操作,這裡成為任務集。每個task運行順序按照playbook文件中從上到下依次運行,當某個task運行出錯時停止(可以使用ignore_erros參數忽略錯誤改變)。每個task須有個name用於標記此次的任務名稱,同時也能友好方便我們閱讀結果。 定義語法: 
tasks:           
    - name: task_name   #任務名稱
      module: module_args #使用的模塊,以及模塊參數,列如yum: name=nginx state=present

示例: 安裝一個httpd服務並啟動: 
---
- hosts: 10.1.210.51
  remote_user: root
  tasks:
   - name: install package   #使用yum安裝包
     yum: name=httpd state=present
   - name: start httpd       #啟動該服務
     service: name=httpd state=started

執行:

variables

  playbook可使用變數來代替某些重覆性的字元串,定義變數方式有多種,而引用變數只需要通過雙括弧引用(Jinji2模版語法),例如:{{ var_name }}。 變數命名僅能由字母、數字和下劃線組成,且只能以字母開頭。 變數定義: 1.直接使用facts 在上一篇文章紅介紹了setup模塊收集facts信息,而這些信息可以用來作為我們playbook的變數使用,例如ansible_all_ipv4_addresses這個facts變數保存的是主機的IP地址。 示例:
---
- hosts: 10.1.210.53
  remote_user: root
  tasks:
    - name: test facts var
      shell: echo "{{ ansible_all_ipv4_addresses }}" > host_ip.txt

2.主機清單中定義變數 格式: 
#單獨主機變數,優先順序高於公共變數
host  varname=value
#主機組變數
[groupname:vars] #為指定主機組自定義變數,vars為關鍵字
varname=value

列如:

vi /etc/ansible/hosts 
10.1.210.51 business=card   #變數名為business值為card
10.1.210.53

[dev]
10.1.210.33
10.1.210.32

[dev:vars]                  #組變數定義
myname=wd

示例:

[root@app52 ~]# cat test.yaml 
---
- hosts: 10.1.210.51
  remote_user: root
  tasks:
    - name: test facts from hosts
      debug: var=business  #使用debug列印變數的值,var參數測試變數不需要用{{ }}

運行playbook:

3.playbook中定義變數

格式:

vars:
  - varname1: value1
  - varname2: value2

示例:

---
- hosts: 10.1.210.51
  remote_user: root
  vars:
    - pkg_name: httpd
    - pkg_cmd: /usr/sbin/httpd
  tasks:
    - name: restart httpd
      service: name={{ pkg_name }} state=restarted
    - name: copy cmd
      copy:  src={{ pkg_cmd }} dest=/tmp/

運行playbook:

4.命令行中定義變數

ansible-playbook -e 'varname=value’  #該方式定義的變數優先順序最高

5.通過文件引用變數。

[root@app52 ~]# cat /tmp/myvars.yml 
var1: value1
var2: value2

playbook中使用

---
- hosts: 10.1.210.51
  remote_user: root
  vars_files:
    - /tmp/myvars.yml      #變數文件
  tasks:
    - name: test myvar
      debug: msg="{{ var1 }}/{{ var2 }}" #這裡的var1變數和var2變數來自於文件/tmp/myvars.yml

運行結果:

6.在roles中定義變數,後續在介紹roles在講解。

Templates

  不同的遠程主機配置文件是一般不相同的,不可能每次都要修改配置文件,所有就出現了模板技術(魔模塊template實現)。通過定義一份模板,在進行配置文件推送時候,會根據我們定義好的變數進行替換,從而達到不同的主機配置文件是不同且符合我們預期的。 templates模版語法採用Jinja2模版語法,參考這裡 使用方法: 1.定義模版,文件名稱必須以.j2結尾
vim /tmp/nginx.conf.j2

user  nginx;
worker_processes  {{ ansible_processor_vcpus }};  #使用cpu個數作為woeker數量
error_log /var/log/nginx_error.log crit;
pid       /var/run/nginx.pid;
include /usr/share/nginx/modules/*.conf;
worker_rlimit_nofile 65535;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    gzip  on;
 server
  {
    listen 80;  
    server_name   {{ ansible_fqdn }} #使用主機名作為hostname
    access_log    /var/log/access.log;
    error_log    /var/log/error.log;
}
}

2.playbook中使用

---
- hosts: 10.1.210.53
  remote_user: root
  vars:
  - package_name: nginx
  - config_path: /etc/nginx/nginx.conf
  tasks:
    - name: install epel
      yum:  name=epel-release
    - name: install package
      yum: name={{ package_name }}
    - name: copy config file
      template: src=/tmp/nginx.conf.j2 dest={{ config_path }} backup=yes #backup用於備份
    - name: start service
      service: name={{ package_name }} state=started

運行playbook

Handlers和notify

  Handlers是task列表,這些task與tasks中的task並沒有本質上的不同,用於當關註的資源發生變化時,才會採取一定的操作。而觸發的行為則是由notify產生,可以理解為notify通知Handlers觸發某個task。     需要註意的是,不管發生多少次notify行為,等到play中的所有task執行完成之後,handlers中的task才會被執行,而這些task只會被執行一次;    notify可以定義多個,多個notify用列表方式來表示。 示例:
- hosts: 10.1.210.53
  remote_user: root
  vars:
  - package_name: nginx
  - config_path: /etc/nginx/nginx.conf
  tasks:
    - name: install epel
      yum:  name=epel-release
    - name: install package
      yum: name={{ package_name }}
    - name: copy config file
      template: src=/tmp/nginx.conf.j2 dest={{ config_path }} backup=yes
      notify:  #當配置文件發生變化時候,通知hanler觸發task
        - stop service
        - start service
  handlers:
    - name: stop service
      service: name={{ package_name }} state=stopped
    - name: start service
      service: name={{ package_name }} state=started

運行playbook

三、playbook進階技巧 

使用tag標記任務

為某個任務打一個標簽,可以使用ansible-playbook 命令選擇性的執行任務。打標簽可通過tags標簽指定,可以是與其相關的參數:
  • --list-tags :列出playbook中所有的tag
  • --skip-tags:跳過playbook中被標記的tag任務
  • -t 或 --tags:指定運行playbook中被標記的tag任務
  以下playbook中分別定義了將兩個tag進行了標記:
---
- hosts: 10.1.210.51
  remote_user: root
  tasks:
    - name: exec tag1
      shell: cat /etc/passwd
      tags: tag1
    - name: exec tag2
      file: path=/tmp/b.txt state=touch
      tags: tag2
    - name: view password
      shell: cat /etc/passwd

列出tag

指定運行某個tag任務

跳過tag任務運行

從以上結果可看出,跳過了tag1和tag2任務,只運行了view password任務。

 

條件測試when

when關鍵字可實現根據某些條件判斷當前的task是否需要執行。when可根據變數、facts(setup)或此前任務的執行結果來作為判斷依據,同時支持邏輯運算符操作,比較強大和實用。 需要註意的是:
  • when判斷的對象是task,所以和tas k在同一列表層次。它的判斷結果決定它所在task是否執行,而不是它下麵 的task是否執行。
  • when中引用變數的時候不需要加{{ }}符號。

示例一:使用facts變數測試

tasks:
  - name: "shut down Debian flavored systems"
    command: /sbin/shutdown -t now
    when: ansible_facts['os_family'] == "Debian"     #當操作系統是Debian才執行該任務

示例二:使用邏輯運算進行多條件判斷

tasks:
  - name: "shut down CentOS 6 and Debian 7 systems"
    command: /sbin/shutdown -t now
    when: (ansible_facts['distribution'] == "CentOS" and ansible_facts['distribution_major_version'] == "6") or
          (ansible_facts['distribution'] == "Debian" and ansible_facts['distribution_major_version'] == "7")

兩個條件使用and還可以如下表示

tasks:
  - name: "shut down CentOS 6 systems"
    command: /sbin/shutdown -t now
    when:
      - ansible_facts['distribution'] == "CentOS"
      - ansible_facts['distribution_major_version'] == "6"  #同時滿足系統是CentOS且版本是6

示例三:根據任務的執行結果狀態來判斷任務是否執行,這裡使用register來保存了任務執行結果,後續會介紹。

---
- hosts: 10.1.210.51
  name: test when
  remote_user: root
  tasks:
    - name: task1
      command: /bin/false
      register: result            #將本次任務結果保存在變數中
      ignore_errors: True          #忽略錯誤執行,可確保任務錯誤也能執行下一個任務

    - name: pre task failed
      file: path=/tmp/failed.txt state=touch    
      when: result is failed          #判斷result結果是否是failed 

    - name: pre task successed state=touch
      file: path=/tmp/success.txt
      when: result is succeeded       #判斷result結果是否是succeeded

    - name: pre task skipped  state=touch
      file: path=/tmp/skip.txt
      when: result is skipped          #判斷結果是否是skipped

運行一下:

如上圖,紅色的部分任務都跳過了未執行,這是因為result結果是failded,所以只執行了“pre task failed”這個任務。

示例4:使用變數進行測試

---
- hosts: 10.1.210.51
  name:  test var when
  remote_user: root
  vars:
    - flag: true        #變數定義
  tasks:
    - name: test server
      ping:
      when: flag        #判斷變數flag為true執行

    - name: create file
      file: path=/tmp/myfile.txt state=touch
      when: not flag    #變數flag不為true執行

執行結果:

同樣可以看到create file 任務被跳過了。

使用register保存任務結果

  register註冊變數,用於保存任務結果,可用於保存配置或when關鍵字判斷,這是非常有用了,在上個示例中使用了任務結果作為判斷條件。例如,你可以將文件中的配置或者json內容保存在變數中,可以供後續使用:

---
- hosts: 10.1.210.51
  name: test register
  remote_user: root
  tasks:
    - name: read conf
      shell: cat /tmp/nginx.conf
      register: nginx_conf  #註冊變數

    - name: copy conf
      copy: content={{ nginx_conf }} dest=/etc/nginx/nginx.conf #使用變數

還可以配合迴圈使用,以下示例展示了批量創建軟鏈接:

- name: registered variable usage as a loop list
  hosts: all
  tasks:

    - name: retrieve the list of home directories
      command: ls /home
      register: home_dirs

    - name: add home dirs to the backup spooler
      file:
        path: /mnt/bkspool/{{ item }}
        src: /home/{{ item }}
        state: link
      loop: "{{ home_dirs.stdout_lines }}"

使用迭代進行重覆性操作或任務

當有需要重覆性執行的任務時,可以使用迭代機制。其迭代的內容會保存在特殊變數item中,ansible提供很多迭代指令,大多都是以with_開頭,以下是幾種常見的迴圈。  1.with_items迭代列表 示例一:創建多個用戶 
---
- hosts: localhost
  remote_user: root
  tasks:
   - name: create user
     user: name={{ item }} state=present
     with_items:
       - zabbix
       - admin

執行結果:

示例二:迴圈中使用register註冊變數

- hosts: localhost
  remote_user: root
  tasks:
     - command: echo {{ item }}
       with_items: [ 0, 2, 4, 6, 8, 10 ]
       register: num
     - debug: msg="{% for i in num.results %} {{i.stdout}} {% endfor %}"

註意,將with_items迭代後的結果註冊為變數時,其註冊結果也是列表式的,且其key"results"。具體的結果比較長,可以使用debug模塊的varmsg參數觀察變數的結果。以上示例運行結果如下:

2.with_dict迭代字典

使用"with_dict "可以迭代字典項。迭代時,使用"item.key"表示字典的key"item.value"表示字典的值。 示例一:
---
- hosts: localhost
  remote_user: root
  tasks:
     - debug: msg="{{ item.key }} / {{ item.value }}"
       with_dict: { ip: 10.1.210.51, hostname: app52, gateway: 10.1.210.1}

以上示例中字典是已經存在了,除此之外字典可以來源於變數、facts等。例如使用facts進行迭代

---
- hosts: localhost
  remote_user: root
  tasks:
    - debug: msg="{{item.key}} / {{item.value}}"
      with_dict: "{{ ansible_cmdline }}"

 

使用include簡化playbook

 如果將所有的play都寫在一個playbook中,很容易導致這個playbook文件變得臃腫龐大,且不易讀。因此,可以將多個不同任務分別寫在不同的playbook中,然後使用include將其包含進去即可。include可以導入兩種文件:導入task文件、導入playbook。

示例:創建task.yml任務列表

vim task.yml
- name: task1
  debug: msg="exec task1"
- name: task2
  debug: msg="exec task2"

在目標playbook中倒入任務

---
- hosts: 10.1.210.51
  remote_user: root
  tasks:
    - include: task.yml

執行playbook:

示例2:直接導入其他playbook,不過在ansible2.8將移除,2.8中將使用import_playbook 

---
- hosts: 10.1.210.51
  remote_user: root
  tasks:
    - include: task.yml

- include: test_when.yml
- include: test_with.yml

四、roles(角色)介紹

簡介

  roles 就字面上來說有角色、作用的意思,但它的全名其實是 Playbooks Roles,我們可把它當成是 playbooks 的延伸使用,可以降低 playbooks 的複雜性,更可以增加 playbooks 的可用性。簡單來講,roles就是通過分別將變數、文件、任務、模板及處理器放置於單獨的目錄中,並可以便捷地include它們的一種機制。

使用場景

  • 同時安裝多個不同的軟體如:LNMP環境
  • 不同伺服器組需要安裝不同服務
  • 複雜的playbook,使用role可以具有閱讀性 

目錄結構

一個角色中目錄包含以下目錄:
  • files:用來存放由copy模塊或script模塊調用的文件。
  • templates:用來存放jinjia2模板,template模塊會自動在此目錄中尋找jinjia2模板文件。
  • tasks:此目錄應當包含一個main.yml文件,用於定義此角色的任務列表,此文件可以使用include包含其它的位於此目錄的task文件。
  • handlers:此目錄應當包含一個main.yml文件,用於定義此角色中觸發條件時執行的動作。
  • vars:此目錄應當包含一個main.yml文件,用於定義此角色用到的變數。
  • defaults:此目錄應當包含一個main.yml文件,用於為當前角色設定預設變數。
  • meta:此目錄應當包含一個main.yml文件,用於定義此角色的元數據信息。

   例如:一個nginx角色的目錄結構可以是:

.
└── nginx
    ├── default
    ├── files
    ├── handlers
    ├── meta
    ├── tasks
    ├── templates
    └── vars

多個role目錄:

├── httpd             #http role
│   ├── default
│   ├── files
│   ├── handlers
│   ├── meta
│   ├── tasks
│   ├── templates
│   └── vars
└── nginx            #nginx role
    ├── default
    ├── files
    ├── handlers
    ├── meta
    ├── tasks
    ├── templates
    └── vars

演示:使用role安裝nginx

一、創建對應的目錄結構:

[root@app52 ~]# mkdir -pv roles/nginx/{files,templates,vars,tasks,handlers,meta,default} 
mkdir: 已創建目錄 "roles"
mkdir: 已創建目錄 "roles/nginx"
mkdir: 已創建目錄 "roles/nginx/files"
mkdir: 已創建目錄 "roles/nginx/templates"
mkdir: 已創建目錄 "roles/nginx/vars"
mkdir: 已創建目錄 "roles/nginx/tasks"
mkdir: 已創建目錄 "roles/nginx/handlers"
mkdir: 已創建目錄 "roles/nginx/meta"
mkdir: 已創建目錄 "roles/nginx/default”

二、定義變數

[root@app52 ~]# vi roles/nginx/vars/main.yml
pkg_name: nginx  #安裝包名稱
listen_port: 80   #監聽埠

三、編寫任務

這裡可以把任務模塊化,最後在main.yml包含它們

[root@app52 ~]# vi roles/nginx/tasks/yum.yml
- name: install epel
  yum: name=epel-release state=present

- name: install nginx pkg
  yum: name={{ pkg_name }} state=present

[root@app52 ~]# vi roles/nginx/tasks/copy.yml 
- name: copy nginx.conf
  template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf

- name: copy index.html
  copy: src=index.html dest=/var/www/html/
  notify: reload

[root@app52 ~]# vi roles/nginx/tasks/start_service.yml 
- name: start nginx
  service: name=nginx state=restarted

[root@app52 ~]# vi roles/nginx/tasks/main.yml 
- include: yum.yml
- include: copy.yml
- include: start_service.yml

四、準備配置文件以及index.html

#index.html
[root@app52 ~]# vi roles/nginx/files/index.html 
<h1>Hello wd</h1>

#配置文件模版
[root@app52 ~]# vi roles/nginx/templates/nginx.conf.j2 
user  nginx;
worker_processes  {{ ansible_processor_vcpus }};  #使用cpu個數作為woeker數量
error_log /var/log/nginx_error.log crit;
pid       /var/run/nginx.pid;
include /usr/share/nginx/modules/*.conf;
worker_rlimit_nofile 65535;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    gzip  on;
 server
  {
    listen {{ listen_port }};
    server_name   {{ ansible_all_ipv4_addresses[0] }} ; #使用IP地址作為server name
    root /var/www/html                ;
    access_log    /var/log/access.log;
    error_log    /var/log/error.log;
}
}

五、編寫handlers

如果在task中使用了notify,則就需要寫對應的handlers,上述我使用了reload這個handler,所以這裡需要定義:

[root@app52 ~]# vi roles/nginx/handlers/main.yml 
- name: reload
  service: name=nginx state=reloaded

六、在角色同級目錄編寫playbook引入角色

[root@app52 ~]# vi roles/install_nginx.yml 
- hosts: web             #指定使用role的主機或主機組
  remote_user: root      #指定用戶
  roles:                 #使用的role,可以有多個
    - nginx

最後的目錄結構為:

[root@app52 ~]# tree roles/
roles/
├── install_nginx.yml
└── nginx
    ├── default
    ├── files
    │   └── index.html
    ├── handlers
    │   └── main.yml
    ├── meta
    ├── tasks
    │   ├── copy.yml
    │   ├── main.yml
    │   ├── start_service.yml
    │   └── yum.yml
    ├── templates
    │   └── nginx.conf.j2
    └── vars
        └── main.yml

8 directories, 9 files

七、運行playbook並測試

如紅色部分,curl測試nginx 安裝成功。 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、set 查看set 幫助: 選項: e:任何命令執行失敗(非0 status)直接退出 x: 列印執行過程的命令行、參數 +e:命令執行失敗不會中斷退出 +x:不列印執行過程的命令行、參數 二、seq seq: 列印數字序列 用法:seq first [incr] last 三、eval && ...
  • 轉載https://blog.csdn.net/weixin_38187469/article/details/79273962 開啟mysql日誌 1、查看日誌是否啟用 mysql> show variables like 'log_bin'; 出現off就代表沒有開啟。 2、編輯my.cnf 退 ...
  • SVN 簡介: Subversion(SVN) 是一個開源的版本控制系統, 也就是說 Subversion 管理著隨時間改變的數據。 這些數據放置在一個中央資料檔案庫(repository) 中。 這個檔案庫很像一個普通的文件伺服器, 不過它會記住每一次文件的變動。 這樣你就可以把檔案恢復到舊的版本 ...
  • 監控項目及使用模板 監控http和https: Template App HTTP Service Template App HTTPS Service 監控cpu,記憶體,網路等: Template OS Linux (Template App Zabbix Agent) 監控埠: Templat ...
  • 今天登錄遠程windows2008系統主機發現出現如下錯誤:要登錄到這台遠程電腦,您必須被授予允許通過終端服務登錄的許可權。預設地,"遠程桌面用戶"組的成員擁有該許可權。如果您不是"遠程桌面用戶"組或其它擁有該許可權的組的成員,或者如 果"遠程桌面用戶"組沒有該許可權,您必須手動授予這些許可權。經過查找中找 ...
  • TMUX天下第一 全世界所有用CLI Linux的人都應該用TMUX,我愛它! 以下是正文 Linux下麵常用的搜索命令有這些:find locate grep which whereis。其中在我用的SuSE上,並沒有locate,所以也不能用它神奇的手動更新資料庫和"高速"索引查找,而grep是 ...
  • 按道理來說zabbix就自帶的MySQL插件來監控mysql資料庫,但是你會發現,自帶的mysql監控項是很少的,根本滿足不了公司的需求。由於它本身自帶的模板太過簡單了,所以需要做更詳細的監控,而percona就提供了這個詳細監控的模版以及腳本,解決了監控不全面的問題。percona插件是安裝在za ...
  • Github 入門 什麼是 Github? github是一個基於git的代碼托管平臺,付費用戶可以建私人倉庫,我們一般的免費用戶只能使用公共倉庫,也就是代碼要公開。 Github 由Chris Wanstrath, PJ Hyett 與Tom Preston-Werner三位開發者在2008年4月 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...