# Linux [TOC] ## LazyVim - Installation - `curl -LO https://github.com/neovim/neovim/releases/download/v0.11.1/nvim-linux-arm64.appimage` - `chmod u+x nvim-linux-arm64.appimage` - `mv nvim-linux-arm64.appimage /usr/bin/nvim` - color - `colorscheme habamax` - usable types : `ls ~/.local/share/nvim/lazy/` - Settings - `LazyExtras` ## tcpdump - `sudo tcpdump -i <interface> dst host 192.168.50.150 and dst port 514` - display all packets send to port 514 : `sudo tcpdump -X -i <interface> udp port 514 -w ~/b.pcap` ## nfs ### 概念 - 讓 node 之間透過網路共享檔案 ### 安裝 - server : `sudo apt install nfs-kernel-server` - client : `sudo apt install nfs-common` ### 設定 - server - 確保 port 開啟 on firewall - Port 111 (TCP and UDP) and 2049 (TCP and UDP) for the NFS server. - `sudo mkdir /var/nfs` - `sudo vim /etc/exports` ```= /var/nfs/ 163.22.17.153(rw,sync) ``` - `sudo systemctl restart nfs-kernel-server` - `sudo exportfs` : 確認設定 - ![image](https://hackmd.io/_uploads/SyaTO8cx1g.png) - client - mount - `sudo mkdir /var/nfs` - `sudo mount 163.22.17.116:/var/nfs /var/nfs` - unmount - `sudo unmount 163.22.17.116:/var/nfs` - <b>當前 shell 不能在 mount 的 path</b> ### ref - https://www.akiicat.com/2019/03/09/DevOps/setup-nfs-server/ ## wildcard dns ```= sudo apt-get install dnsmasq sudo echo "address=/.example.com/127.0.0.1" >> /etc/dnsmasq.d/weblocal ``` - `vi /etc/resolv.conf` ```= nameserver 127.0.0.1 nameserver 8.8.8.8 nameserver 8.8.4.4 ``` - `vi /etc/dnsmasq.conf` ```= address=/.s3.hicloud.net.tw/192.168.17.138 address=/s3.hicloud.net.tw/192.168.17.138 ``` - `sudo /etc/init.d/dnsmasq restart` ## GlusterFS ### 概念 - 這敘述不太正確 - 分散式儲存和分散式檔案系統最大的區別,檔案系統是可以掛載的,而儲存則是無檔案系統入口的,所以只可以透過API來訪問,常見的分散式儲存有: - GFS: Google File System - 分散式的鼻祖等級系統,由Google內部開發,發表有技術實作論文,為後來的分散式儲存系統提供了技術實作基礎 - HDFS: Hadoop Distribution File System - Hadoop的分散式儲存系統,透過GFS的論文的開源實現 - GlusterFS - 不溫不火的分散式儲存系統,被redhat收購,去中心化,沒有元資料節點 - Ceph - Linux內核級的實現的分散式檔案系統,收錄Linux內核,正在被廣泛的試驗,未來的新貴 - MogileFS - 適合儲存海量小文件,使用perl語言編寫,有人使用c語言重寫並開源為FastDFS - TFS - Taobao FileSystem,基於HDFS開發適合儲存海量小文件 ### 架構 - ![image](https://hackmd.io/_uploads/S1MABv9lkl.png) - brick - 在意思上為儲存區,也就是設定好 LVM 並完成格式化之後的可用邏輯磁碟區。 - 所有 Client 的檔案都會被放在 Brick 上,Brick 所提供的容量大小是由 LVM 設定而來,所以當單一個 Brick 損毀或空間滿的時候,只會照成部份的檔案不見或無法寫入,而不是所有檔案都會遺失。 - volume - Volume 也就是最終 Client 可以使用的項目,設定好 Volume 之後只要在 Client 端使用 mount 指令就可以使用 Gluster 檔案系統,而在 Client 所看到的可用容量自動計算其 Brick 成員加總而成的總空間大小。 - 一個 Volume 是由多個 Brick 所組成的,依據其 Volume 的分散式狀態所得的可用空間也不一樣,比如設定 Volume A 是由 brick1(10GB) 與 brick2(10GB) 使用分散式設定,那麼會得到 10GB + 10GB = 20GB 的總容量;若是使用複寫式,則會因為資料同時保留兩份在不同 Bricks 中,所以其容量也只會有 10GB。 ### ref - https://www.l-penguin.idv.tw/book/Gluster-Storage_GitBook/gluster_intra/gluster_arch.html - https://glusterdocs.readthedocs.io/en/latest/Administrator%20Guide/GlusterFS%20Introduction/ ## 筆記 1. 軟連結 - 建立, 把現在這個目錄下的 text.txt 連結到 root 下的 text.txt ln -s text.txt /root/text.txt - 刪除, 把現在這個目錄下的 text.txt 的軟連結刪除 rm -rf ./text.txt - 全部刪除, 把現在這個目錄下的 text.txt 的軟連結刪除以外, 還會把原本連結到的檔案刪除 rm -rf ./test_chk_ln/ 2. 刪除目錄 - 空目錄 rmdir - 不一定要空的目錄 rm -rf 3. 查看監聽 port netstat -tulpn grep :80 4. 複製文件 - ex. 複製這個目錄下的 a.py 到 ~ 下的 a.py cp a.py ~/a.pyi 5. tab*2 查詢指令、資料夾 - 搜尋指令,第一個字的後面兩個 tab ex. ca[tab][tab] - 搜尋檔案,第二個字後面兩個 tab cat ~/[tab][tab] 6. 虛擬環境 pip install 出現 permissionError denied - 教學 https://blog.csdn.net/Yonggie/article/details/114327306 - 原因 該帳號不是最高級別用戶 - 變更為 root 權限帳號(需輸入 root 密碼) su - - 若沒有 root 密碼,需先建立一個 sudo passwd root 7. scp 到指定 port - 複製本地檔案到遠端 ex. scp -P 6653 /file root@xxx.xxx.xx:/file - 複製遠端檔案到本地 ex. scp -P 6653 root@xxx.xxx.xx:/file /file - not a regular file 加上 -r 參數 scp -r -P 6653 /file root@xxx.xxx.xx:/file 8. 清理 journal - 教學 https://www.peterdavehello.org/2020/01/clean-up-linux-systemd-journal-logs/ 9. 查看 host 容量 - `df -h` 10. 查看檔案大小 - ex. `du -sh ./*` - `-h` : human readable - `-s` : 只顯示總和不顯示其子目錄下的檔案 10. 檔案權限 - 查看 ls -l - 意義 r = 可讀, 權限值 = 4 w = 可改, 權限值 = 2 e = 可執行, 權限值 = 1 順序分別為 user, group, others 有時候執行也需要可讀 ex. -rwxr----- = 相同 user 可讀寫執行、相同 group 可以讀、其他不能寫讀執行 - 增加權限 : chmod - 規則 : r屬性值:4, w屬性值:2, x屬性值:1 ex. chmod 750 = user 可讀寫執行、相同 group 可以讀寫、其他不能寫讀執行 - 四碼代表的意思 : 4000 Sets user ID on execution 2000 Sets group ID on execution 1000 Sets the link permission to directoires or sets the save-text attribute for files. ex. 4771 : 代表其他使用者在執行此檔案的時候會有 user 的權限。 11. 找檔案內容 https://www.codingsusu.com/find-all-files-containing-specific-text-on-linux/ `grep -rnw 'path' -e 'text'` 12. 查看 ram 狀況 - free - 看幾 g : `free -g` 13. 查看目前使用者 w 14. 寫入內容到那個使用者的 terminal sudo write user TTY 15. 查看指定 port netstat -tulpn | grep :80 16. 管理 gitlab - 開啟 sudo gitlab-ctl start - 關閉 sudo gitlab-ctl stop 17. ln, 連結 ln test.py test2.py # 把 test2.py 硬連結到 test.py ln -s test.py test2.py # 把 test2.py 軟連結到 test.py - 軟連結 inode 不同,可以連結整個資料夾,原檔案刪除後被連結的檔案內容會消失,不太佔硬體空間 - 硬連結 inode 相同,不可以連結整個資料夾,原檔案刪除後被連結的檔案不會消失,原檔案消失前不會佔硬體空間 18. sync, 資料同步 linux 會把資料放在 ram 的 buffer,所以在關機之前需要把資料同步回去硬碟。 19. passwd, 改密碼 20. 壓縮 - gzip gzip test.py # 壓縮 gzip -d test.py.gz # 解壓縮 - xz xz test.py # 壓縮 xz -d test.py.xz # 解壓縮 - tar tar cvf trat.tar test.py # 壓縮 tar xvf test.tar # 解壓縮 tar xvf test.tar.gz # 也可以直接解 .gz tar zcvf FileName.tar.gz DirName 壓縮不包含父目錄 : `tar -czvf xxx.tar.gz -C /ebs1/xxx/aaa/bbb .` - 7zip - 解壓縮,依照原本檔案格式 : `7z x file.7z` - 這樣會全部解在當前目錄 `7z e file.7z` - grep grep -r 'tommy' * # 要找資料夾要 -r, * 代表從根目錄找 - flush dns sudo systemd-resolve --flush-caches - 安裝 vm : 如果看不到安裝的按鈕,可以用 tab,要注意的是有些是取消、上一步、下一步、安裝 - 查看使用者帳號密碼 - 有加密過的, 不須 sudo ``cat /etc/passwd`` - 沒加密的, 要 sudo ``sudo cat /etc/shadow`` - 軟連結(soft link) vs 硬連結(hard link) - 軟連結 : 常用於當作捷徑 1. 刪掉母體, 分身會消失 2. 改母體或分身, 兩個的內容都會一起變 - 硬連結 : 常用於備份 1. 刪掉母體, 分身不會消失 2. 改母體或分身, 兩個的內容都會一起變 - 把檔案變成執行檔 : `sudo chmod +x xxx` # xxx = 檔案名稱 - 執行 : 在和執行檔同個路徑下 `./xxx` - 變成所有使用者都可以直接呼叫檔名執行 : 把執行檔複製到 /usr/local/bin - `sudo cp xxx /usr/local/bin/` - 網段 - 判斷此網段有多少 ip : 看遮罩到第幾個 bit,總共會有 4*8 = 32 個 bits,若剩下可以用的有 n 個 bit,就是 2 的 n 次方 - network id : 該網段的第一個 ip。 - broadcast id : 該網段的最後一個 ip - netmask : 遮罩, ip = 不能使用的 bit 用 1 填滿, 代表總共有多少個 ip 可以使用 - 教學 https://ithelp.ithome.com.tw/questions/10153316 - ex. 1. 255.255.255.0 有 255 個 ip(255.255.255.255-255.255.255.0) 2. 255.255.255.248 有 7 個 ip(255.255.255.255 - 255.255.255.248 = 7) - 實際範例 : 有一個網段 123.45.67.89/26 - 此網段總共有多少 ip : 被遮掉 26 bits,所以剩 6 個 bits,ans : 2^6 = 64。 - network id : 123.45.67.89 = x.x.x.01011001,ans : 123.45.67.01000000 = 123.45.67.64 - broadcast id : 123.45.67.89 = x.x.x.01011001,ans : 123.45.67.01111111 = 123.45.67.127 - netmask 遮罩 : ans : 11111111.11111111.11111111.11000000 = 255.255.255.192 - iptables : - Chain : 時間點 - `FORWARD` : 轉送封包,沒有進去 firewall 的主機 - `INPUT` : 進去 firewall 的主機。ex. 直接 ssh 進這台主機 - `OUTPUT` : 主機送出的封包 - `PREROUTING` : 在接收封包之前 - `POSTROUTING` : 在送出封包之前 - table : - filter : `sudo iptables -t filter` # 預設是 filter,所以也可以不寫 - nat : `sudo iptables -t nat` # 只有當需要換 ip 位址才要用,ex. SNAT、DNAT、MASQUERADE - MASQUERADE : 把送出去的封包的內網 ip,轉成外部 ip,讓 destination 可以知道要送回的 ip - 範例 : `sudo iptables -t nat -I POSTROUTING -o {wan nic} -j MASQUERADE` - 紀錄連線的狀態 : `conntrack` - 規則 : ```= NEW: 新的連線 ESTABLISHED: 已建立的連線 RELATED: 與 ESTABLISHED 連線有關的連線 INVALID: 無效 ``` - 範例 : 允許轉送已建立連線的封包(允許送出去的封包回的來) `sudo iptables -A FORWARD -m conntrack --ctstate "ESTABLISHED,RELATED" -j ACCEPT` - 列出每個 chain 的規則 : `iptables -L INPUT -n --line-numbers` # -n --line-numbers = 印出行號 - 刪除對應 chain 的規則 : `sudo iptables -D CHAIN的種類 列出的num` - ex. : `sudo iptables -D INPUT 1` - debug : `sudo iptables -nvL`,可以看bytes有沒有增加 - sudo iptables -L 列出 filter 三個 chain 的規則 - proxy, 代理 - 正向代理 : 客戶藉由一台正向代理的機器向伺服器端取得資料。代理客戶端去和伺服器端拿資料,有點類似跳板機。 - 反向代理 : 客戶向一台反向代理的機器拿資料,那台再向伺服器端(通常會有多台伺服器)拿資料。代理伺服器端回傳資料給客戶,通常用於負載平衡。 - 雲端 vm - 教學 : https://ithelp.ithome.com.tw/articles/10219735 - nginx - check config nginx syntax `sudo nginx -t` - 改 port : 1.`sudo vi /etc/nginx/sites-available/xxx` # xxx = 設定檔名,預設有一個 default 設定檔 2. 把 listen 的後面的數字改為要去的 port - 讓 available 寫的 conf 檔生效 : 把設定檔軟連結到 sites-enable `ln -s /etc/nginx/sites-available/www.example.org.conf /etc/nginx/sites-enabled/` # 一定要用絕對路徑 - 改預設 html 位置 - ex. 把預設(/var/www/html/index_nginx.html)改為 /var/www/nginx/xxx.html # xxx = 某個 html 檔 ```= root /var/www/nginx; index xxx; server_name lsa.lab; location / { try_files $uri /xxx.html =404; # 這行記得把第二個 $uri 改成要去的 .html } ``` - proxy settings : - 教學 : https://sharefunyeh.gitbooks.io/webdev/content/articles/understand-nginx-proxy-load-balancing-buffer-and-cache.html - 實作 : ```= # the url on upstream and server no need to add the https or http, as will add default upstream ammon.bluet.org { # this is like domain name, so must be same as the proxy_pass's url without the http/s server tw.search.yahoo.com.; server ammon.bluet.org; } server { listen 8070; server_name localhost; location / { # 這邊也可以改為 http://w/ or http://s 之類的,但上面 upstream 就要改為 w or s proxy_pass http://ammon.bluet.org/; } } ``` - certbot : - 教學 : https://abstreamace.com/sglab/2021/02/04/%E6%9B%BF-ubuntu-nginx-%E5%8F%96%E5%BE%97%E5%85%8D%E8%B2%BB-ssl-%E6%86%91%E8%AD%89%EF%BC%88%E4%BD%BF%E7%94%A8-certbot%EF%BC%89/ - `sudo snap install --classic certbot` - `sudo ln -s /snap/bin/certbot /usr/bin/certbot ` - 把目前的 .conf 檔中的內容產生憑證 : `sudo certbot --nginx` - ssh - 一般連線 : `ssh ann@172.0.2.15` # 使用者名稱@ip - local tunel : 把本地的某個 port 連到另外一台機器的 port 上。 - 語法 : `ssh -L <local IP>:<local port>:<target IP>:<target port> <target server user name>@<target IP> - 範例 : 要把本地的 8080 port 連到 163.22.32.40 的 5000 port - `ssh -L 8080:0.0.0.0:5000 wang@163.22.32.40` - remote tunel : 和 local tunel 相反,把本地的某個 port 讓另一台機器的 port 連上。 - 語法 : `ssh -R <server IP>:<server port>:localhost:<localhost port> jump@192.168.0.105 -Nf` - 只綁定遠端的 127.0.0.1 - By editing the SSH config file (usually `/etc/ssh/sshd_config` on Linux), you can set the `GatewayPorts` to `yes` and then it should allow SSH tunnels to listen on the other interfaces. - 用憑證連線,不用輸入密碼 : 1. (在本機) `ssh-keygen -t rsa` # 用 tsa 加密 2. (在本機複製公鑰) 複製 `~/.ssh/id_rsa.pub` 3. (在要連線的) `ssh-keygen -t rsa` # 用 tsa 加密 4. (在要連線的) `sudo vi ~/.ssh/authorized_keys`,貼上剛剛在本機複製的 public key - forward agent : - 說明 : 把私鑰帶者跑, 就不用重新輸入密碼。 - 實際情況 : 先 ssh 到一台 server, 再 ssh 到另一台的時候, 如果沒有 ssh forwarding agent 把私鑰帶著跑, 另一台不會知道你原本(本地)是誰, 所以會需要再輸入密碼。 - 步驟 : 1. `eval $(ssh-agent)`: 啟動 ssh-agent 2. `ssh-add ~/.ssh/id_rsa`: 將要 forwarding 的 private key 加到清單內 3. `ssh-add -L`: 檢視是否更新成功 4. `ssh -A user@<server1 ip>` : -A 代表用 forward agent 的方式 ssh - 背景執行 : `-f` - ex. 想要 3009 port 導向其他 vm 的 3009 port 上的服務 - `ssh -fNL 0.0.0.0:3009:0.0.0.0:3009 tommygood@163.22.32.40` - ssh server 會 listen 若 client 超過一定時間沒送 data 會斷開連線。所以若要保持連線就要調整一下: - 從 client 端 - `vi ~/.ssh/config` ```= # 每60秒發送一次keep alive封包 ServerAliveInterval 60 # 斷開時重新連接的次數 ServerAliveCountMax 5 ``` - 或是僅此次連線帶參數就好 - `ssh -o ServerAliveInterval=60 user@remote_host` - 從 server 端 - `vi /etc/ssh/sshd_config` ```= # 將超時設定為600秒(10分鐘), 最大允許3次 ClientAliveInterval 600 ClientAliveCountMax 3 ``` - ref - https://vocus.cc/article/64cb99ecfd89780001cf3ede - apache2 - 改 port : 1. sudo vi /etc/apache2/ports.conf 2. sudo vi /etc/apache2/sites-available/000-default.conf - 改預設 html 位址: `sudo vi /etc/apache2/sites-available/000-default.conf` 的 DocumentRoot(先確定有這個資料夾) - check config syntax : `sudo apachectl configtest` - lighttpd - 改 port : `sudo vi /etc/lighttpd/lighttpd.conf` 的 server.port - 改預設 html 位址: `sudo vi /etc/lighttpd/lighttpd.conf` 的 server.document-root - useradd vs adduser : - useradd : 只會新增使用者,不會新增他的家目錄。 - ex. 1. `sudo useradd tommy` # 設帳號 2. `sudo passwd tommy` # 設密碼 - adduser : 新增使用者,也會新增他的家目錄。 - ex. `sudo adduser tommy` - 給 root 權限 - `sudo vim /etc/sudoers` - ex. 新增 jerry - ![](https://i.imgur.com/vHbdcoy.png) - 覆寫 : `wq!` - 一登入就執行指令 : - `sudo vi /etc/profile` - 輸出文字 : 加 `echo "Welcome"` 在最後一行 - 執行指令 : 直接加在最後一行,ex. `exit` - 讓加入的使用者自動新增檔案 - 在 /etc/skel 裡新增要讓新的使用者有的檔案,就可以讓新的使用者的家目錄下自動產生一個一樣的檔案 - ex : `sudo vi /etc/skel/readme.txt` - 從 log 分析 request 次數 - https://serverfault.com/questions/226982/how-to-measure-req-sec-by-analyzing-apache-logs - ftp - 指令教學 : https://www.ltsplus.com/linux/linux-ftp-command - 教學 : - http://old.linux.vbird.org/linux_server/0410proftpd.php - https://www.ltsplus.com/linux/linux-ftp-command - 登入方式 - `ftp localhost` - vsftpd - 安裝 - `sudo apt install vsftpd` - 設定檔 - 路徑 : `/etc/vsftpd.conf` - 可以寫入 - `write_enable=YES` - 限制 port ``` pasv_min_port=2121 pasv_max_port=2142 ``` - 限制使用者只能用自己的家目錄 ``` chroot_local_user=YES allow_writeable_chroot=YES ``` - 開放防火牆 - `sudo ufw allow ftp` - fail2ban - `sudo vi /etc/fail2ban/jail.conf` ``` [vsftpd] enabled = true ``` - `sudo systemctl restart fail2ban` - rkhunter : 檢查是否有 rootkit(惡意攻擊取得 root 權限的軟體) - 教學 : https://linux.vbird.org/linux_server/others/0420rkhunter.php - 安裝 : `sudo apt install rkhunter` - 執行 : `sudo rkhunter -c` # -c = check all - 固定 ip 教學 : https://www.ltsplus.com/linux/rhel-centos8-setup-static-ip - 先找出 default gateway : `ip route | grep default` - 再找出網卡 : `ifconfig` - 設定固定 ip 及 default gateway(上面找到的) : `nmtui edit enp0s3` # 用剛剛找到的網卡 - 重啟網路 - 檢查對外流量 : `netstat -anpt` - 給 root 權限 : `sudo usermod -aG sudo user_name` - ufw : - 教學 : https://blog.tarswork.com/article/ubuntu-firewall-setting-using-ufw/ - 查看規則 : `sudo ufw status` - 新增規則 : - 允許特定 ip 到特定 port : `ufw allow from 192.168.0.1 to any port 3306` - 允許特定 ip 到所有 port : `ufw allow from 192.168.0.1` - 允許通過 80 Port 使用 tcp 與 udp 連線 : `ufw allow 80` - 允許通過 80 Port 使用 tcp : `ufw allow 80/tcp` - 刪除規則 - `sudo ufw status numbered` - `sudo ufw delete rule_num` - firewalld - 安裝 - `sudo dnf install firewalld -y` - `sudo systemctl enable firewalld` - `sudo systemctl start firewalld` - 查看規則 : `sudo firewall-cmd --list-all` - 新增 : `sudo firewall-cmd --permanent --add-port=1883/tcp` - 刪除 : `firewall-cmd --zone=public --remove-port=12345/tcp --permanent` - 修改皆要 reload : `sudo firewall-cmd --reload` - 關掉後無法打開 - `sudo systemctl stop firewalld` - `sudo pkill -f firewalld` - `systemctl start firewalld` - DNS : 17.131 - 更新步驟 - `sudo rndc freeze im.ncnu.edu.tw` - 編輯設定網域 zones:`sudo vim /etc/bind/zones/db.im.ncnu.edu.tw` A. 新增Domain B. 修改Serial 年/月/日/修改次數 * 查 A(v4) AAA(v6) CNAME C. 存檔離開 `sudo rndc reload im.ncnu.edu.tw` `sudo rndc thaw im.ncnu.edu.tw` `sudo service bind9 reload` - im - ![](https://hackmd.io/_uploads/rkJQGegG6.png) - 移除目前使用者 - 先查看 : `w` - 踢除 : `sudo pkill -kill -t pts/2` - 釋放 snapd 的 cache - `sudo bash -c 'rm /var/lib/snapd/cache/*'` - https://askubuntu.com/questions/1371833/howto-free-up-space-properly-on-my-var-lib-snapd-filesystem-when-snapd-is-unava - 更新 java 版本 - 看一下目前版本 : `java --version` - 下載新版 java : ex. `sudo dnf install java-11-openjdk-devel -y` - 更新 java 版本 : `update-alternatives --config java` - ![image](https://hackmd.io/_uploads/Bk5mxjFexe.png) - 選擇自己要的版本 - 有 process id 可以去 `/proc/{process_id}` 查看資訊 - get ip : `hostname -I` - 導向修理網址 - 建立修理的內容 - `sudo mkdir /var/www/fixed` - `sudo vi /var/www/fixed/index.html` - 新增以下 : `vi /etc/apache2/sites-available/xxx.conf` ```conf= <LocationMatch ".*"> Alias "/var/www/fixed/index.html" </LocationMatch> <LocationMatch "/fixed.jpg"> Alias "/var/www/fixed/fixed.jpg" </LocationMatch> ``` - `sudo systemctl reload apache2` - arp - arping : `arping ip` - 有時候 ping 不到可以用此,比較底層的協定 - 因 ping 是 icmp,可以被關掉 ## vim - tab = 4 space ```config= set smartindent set tabstop=4 set shiftwidth=4 set expandtab ``` ## C - 編譯 ``gcc -g -Wall HelloWorld.c -o HelloWorld`` 當中的「-g」是加入除錯資訊;「-Wall」是顯示所有的警告訊息 ;「-o」用來指定所生成的可執行程式的文件名(Helloworld) - & - 意義 - 取該變數的位址 - scanf 因為要把值存入此變數的位址,所以要用 &。而 printf 因為要取這個變數的值,所以不用 - pointer (指標) - 意義 - 變數的位址 - ex. ```c= int b = 2; // 兩種都可 int* pointer = &b; int *pointer = &b; ``` - array - 宣告 ```c= int test[5]; // 大小為 5 的 int array int arr[] = {3, 4, 5, 6, 7}; ``` - parameter in funcion ```c= int test(int now[]) { } ``` # Docker - 安裝 : - `sudo apt-get update` - `sudo apt install docker.io` - 把使用者加入 docker 群組 - `sudo usermod -aG docker $USER && newgrp docker ` - 基本指令 : - 檢查有沒有啟動 : `docker status` - 下載映像檔 : `sudo docker pull ubuntu` - 查看當前映像檔 : `sudo docker images` - 查看有哪些可用的映像檔 : `sudo docker search` - ex. `sudo docker search httpd` - 刪除映像檔 : `sudo docker rmi image_id` - 複製本地檔案到 container : `sudo docker cp myfile.txt container_name:/usr/share` - 把 image 跑起來 : ``` sudo docker run -itd \ --name test_web_server \ -p 8085:80 \ -v /home/user/website/:/usr/local/apache2/htdocs/ \ docker.io/httpd:latest ``` - 查看當前在跑的 container : `sudo docker ps -a` - 停止目前在跑的 container : - 單一的 : `docker stop container_id` - 所有的 : `docker stop $(docker ps -a -q)` - 刪除目前 container : - 單一的 : `docker rm container_id` - 所有的 : `docker rm $(docker ps -a -q)` - 查看 container log : `sudo docker logs container_id` - 進入 container : `sudo docker exec -it ubuntu bash` - docker-compose : - 安裝 : - `sudo curl -L "https://github.com/docker/compose/releases/download/1.10.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose` - `sudo chmod +x /usr/local/bin/docker-compose` - `sudo docker-compose -v` - 跑起來 : `sudo docker-compose up -d` - 若有更新 docker-compose,也是下這指令,docker 會只針對有更新的地方更新,舊的不會動。 - 暫時停止(不刪除): `sudo docker-compose stop` - 停止並刪除 container、network... : `sudo docker-compose down` - 安裝套件 : - 先進 cotainer : `sudo exec -it container_name bash` - 更新 apt : `apt-get update` - 安裝套件 : `apt install xxx` - 查看 ip : - `docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' container_name_or_container_id ` - wordpress : `docker-compose.yml` + `uploads.ini` - `mkdir wordpress` - `cd wordpress` - `vi docker-compose.yml` : - 注意 : - 第四行 db 和 16 行 wordpress <b>不</b>要改。外接的 ports 要改,不能重複、container_name要改、volumes 的外部路徑也要改。: https://ithelp.ithome.com.tw/articles/10281462 - 如果原本有 db_data,要先 rm 掉。(重要!如果沒 rm 會有問題 ex. 空白畫面) ```= version: '3' services: db: image: mysql:5.7 container_name: mysql_wordpress_3 volumes: - /var/www/docker/wp_4/db_data:/var/lib/mysql restart: always environment: MYSQL_ROOT_PASSWORD: wordpress_root_password MYSQL_DATABASE: wordpress_db MYSQL_USER: wordpress_user MYSQL_PASSWORD: wordpress_password wordpress: container_name: wordpress_3 depends_on: - db image: wordpress:latest ports: - "8891:80" restart: always volumes: - ./uploads.ini:/usr/local/etc/php/conf.d/uploads.ini - ./ai1wm-backups:/var/www/html/wp-content/ai1wm-backups environment: WORDPRESS_DB_HOST: db:3306 WORDPRESS_DB_USER: wordpress_user WORDPRESS_DB_PASSWORD: wordpress_password WORDPRESS_DB_NAME: wordpress_db volumes: db_data: {} ``` - `- ./ai1wm-backups:/var/www/html/wp-content/ai1wm-backups` : 掛載備份檔。不是英文 `l`,是數字 `1` - 如果是之後才加 - 要先進去 container 把原本的 `ai1wm-backups` 改成別的名字,`docker-compose up -d` 後再改回來。 - `docker-compose up -d` 完後,要進 container 把 `ai1wm-backups` 的權限改回來 `chown www-data:www-data ai1wm-backups` - ` vi uploads.ini` : 更改傳輸檔案上限 : - `vi /usr/local/etc/php/conf.d/uploads.ini` ``` file_uploads = On upload_max_filesize = 2000M post_max_size = 2000M memory_limit = 128M ``` - 如果是一開始沒有一起 up 的話,就要新增和更新 - `sudo docker exec -it container_name bash` - `vi /usr/local/etc/php/conf.d/uploads.ini` ``` file_uploads = On upload_max_filesize = 2000M post_max_size = 2000M memory_limit = 128M ``` - `exit` - `sudo docker restart container_name` - 最後用 docker-compose 跑起來 : `sudo docker-compose up -d` - 訪問該位址 : `http://ip:port` - 改用 domain name : - dns server 先將新的 domain name 指向裝此 wordpress 的 server 的 ip - 在 config 變更 domain name : - `sudo docker exec -it wordpress_im_department` - `sudo vi wp-config.php` : 要加在最上面(`<?php` 後面) ```php= <?php define( 'WP_HOME', 'http://example.com' ); define( 'WP_SITEURL', 'http://example.com' ); ``` - `service apache2 reload` - nginx domain name : https://www.youtube.com/watch?v=SLejN0yC8sM - `sudo vi /etc/nginx/sites-available/xxx` ```conf= server { server_name test.im.ncnu.edu.tw; location / { proxy_pass http://163.22.17.234:8888; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Host $server_name; proxy_set_header X-Forwarded-Proto $scheme; } listen 80; } ``` - `sudo ln -s /etc/nginx/sites-available/xxx /etc/nginx/sites-enabled/` - `sudo systemctl reload nginx` - 訪問該 domain : `http://{domain_name}` - 用 certbot 獲得 ssl 憑證 : `sudo certbot --nginx` - 選擇該 domain name 的號碼 - ssl 教學 : https://www.youtube.com/watch?v=T7flzYEtMGA - `vi wp-config.php` : 最上面新增 ```php= if ($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') $_SERVER['HTTPS']='on'; if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) { $_SERVER['HTTP_HOST'] = $_SERVER['HTTP_X_FORWARDED_HOST']; } ``` - `service apache2 reload` - 訪問 https : `https://{domain_name}` - elementer 進不去 : https://juhui.com.tw/elementor-%E4%B8%80%E7%9B%B4%E8%BD%89%E5%9C%88%E5%9C%88-%E7%84%A1%E6%B3%95%E7%B7%A8%E8%BC%AF/ - 暫時解 - `sudo vi /var/www/intern/wp-includes/default-constants.php` : 改成 512 M - ![](https://i.imgur.com/cC3CPVm.png) - `sudo systemctl reload apache2` - 可能會因為 wordpress 更新版本而設定檔跑掉就又要重調 - 應該是根本解 - `sudo vi /var/www/intern/wp-config.php` - 新增 : `define('WP_MEMORY_LIMIT', '512M');` - ![](https://hackmd.io/_uploads/rkaOGwVr3.png) - `sudo systemctl reload apache2` - 無法手動新增外掛 - 自己丟到 wp-content/plugins - `sudo docker cp plugin_name docker_name:/var/www/html/wp-content/plugins` - 記得更改權限 - `sudo dokcer exec -it container_name bash` - `cd /var/www/html/wp-content/plugins` - 看一下新增的套件,權限應該是 root - `ls -l` - 改權限成 web server - `chown -R www-data:www-data plugin_name` - all in one migration - 手動放還原檔 - `sudo docker cp xxx.wpress container_name:/var/www/html/wp-content/ai1wm-backups` - 會有某些圖檔不見 - 因為檔名中包含中文,所以編碼後會有問題 - 解法 1. 把 `wp-content/uploads/` 直接複製到新的主機 - https://www.johntool.com/all-in-one-wp-migration-limit/ 2. 重新上傳圖片 3. 把原本的 wordpress 有用到中文的檔名改為英文後再輸出一次 - 要加在其在 nginx 的設定檔 ```conf= location = /xmlrpc.php { deny all; access_log off; log_not_found off; return 444; } location ~ /\.ht { deny all; } client_max_body_size 64m; ``` - 更換 domain name - 新增其 nginx 的 設定檔 - `sudo ln -s /etc/nginx/sites-available/xxx /etc/nginx/sites-enabled/` - `sudo systemctl reload nginx` - 開無痕 get 一下該 url - 可以的話就 : `sudo certbot --nginx` - 最後進到 container 改 define 的 domain name : `vi wp-config.php` - 新增寄信功能 - 教學 : https://weblai.co/smtp-tutorial/ - ex. `SMTP 使用者名稱` : tommy50508@gmail.com - nginx manager 教學 : https://medium.com/@jmpinney/multiple-wordpress-sites-on-one-server-with-docker-6fb53adc4bfe - docker-compose : ```= version: "3" services: app: image: 'jc21/nginx-proxy-manager:latest' restart: unless-stopped ports: # These ports are in format <host-port>:<container-port> - '80:80' # Public HTTP Port - '443:443' # Public HTTPS Port - '81:81' # Admin Web Port # Add any other Stream port you want to expose # - '21:21' # FTP # Uncomment the next line if you uncomment anything in the section # environment: # Uncomment this if you want to change the location of # the SQLite DB file within the container # DB_SQLITE_FILE: "/data/database.sqlite" # Uncomment this if IPv6 is not enabled on your host # DISABLE_IPV6: 'true' volumes: - ./data:/data - ./letsencrypt:/etc/letsencrypt ``` - php + apache : - docker-compose.yml ```config= version = '3' services : server : image : php:apache container_name : server_im_warehouse ports : - 8890:80 volumes : - ./test:/var/www/html db: image: mysql:5.7 container_name: mysql_im_warehouse volumes: - /var/www/im_warehouse/db_data:/var/lib/mysql restart: always ports: - "3308:3306" environment: MYSQL_ROOT_PASSWORD: jim_tsai MYSQL_DATABASE: im_warehouse MYSQL_USER: im_warehouse MYSQL_PASSWORD: jim_tsai ``` - install mysqli : - `sudo docker exec -it server_im_warehouse bash` - `docker-php-ext-install mysqli` - `docker-php-ext-enable mysqli` - `sudo docker restart server_im_warehouse` - mysql : - 備份 : https://gist.github.com/spalladino/6d981f7b33f6e0afe6bb `docker exec CONTAINER /usr/bin/mysqldump -u root --password=root DATABASE > backup.sql` - 還原 : https://gist.github.com/spalladino/6d981f7b33f6e0afe6bb `cat backup.sql | docker exec -i CONTAINER /usr/bin/mysql -u root --password=root DATABASE` - ex. `sudo cat im_warehouse.bak | sudo docker exec -i mysql_im_warehouse /usr/bin/mysql -u im_warehouse --password=jim_tsai im_warehouse` - 中文亂碼問題 : - 編碼改成 utf-8 : `sudo vi mysql.cnf` ```conf= [mysql] default-character-set=utf8 [mysqld] collation-server = utf8_unicode_ci init-connect='SET NAMES utf8' character-set-server = utf8 [client] default-character-set=utf8 ``` - 複製到 container 裡面 : `sudo docker cp mysql.cnf mysql_im_warehouse:/etc/mysql/mysql.conf.d` - `sudo docker restart mysql_im_warehouse` - 登入 - `sudo docker exec -it container_name bash` - `mysql -u 帳號 -p` - 帳號密碼在 docker-compose.yml - 重灌 docker(把 image, container... 都砍光) - `docker system prune` - 如果系統容量滿到動不了,然後 docker 這時又是關的也開不起來 - 自己去 `/var/lib/docker/containers` 砍一些 container,再把 docker 打開後再 `prune` ## note - container 沒有 ping - `apt update` - `apt install iputils-ping` ## dockerfile - multi stage - 在專案開發時,通常會執行代碼檢查、單元測試、編譯、執行等等,將這些流程步驟撰寫成 dockerfile 直接在容器裡執行衍伸出了新的問題。 - 為了執行代碼檢查和編譯,下載了許多套件或是相依工具,造成映像檔肥大,很多套件或是相依工具在部署時是不需要的。 - ex. ```= FROM golang:1.16.0-alpine3.13 AS builder WORKDIR /workspace/example ENV GO111MODULE=on CGO_ENABLED=0 # download dependency COPY go.mod go.sum . RUN go mod download RUN go install honnef.co/go/tools/cmd/staticcheck@v0.1.2 COPY . . RUN go vet ./... && staticcheck ./... && go test ./... && go build -o /bin/server FROM alpine:latest AS release # Copy from builder COPY --from=builder /bin/server /bin/server ENTRYPOINT ["./bin/server"] ``` - 教學 - https://ithelp.ithome.com.tw/articles/10191016?sc=hot - `docker build -t mytomcat . --no-cache` - - 上傳到 docker hub 1. 先到 docker hub 開一個 repo 2. `docker tag {image_name} {dockerhub_account}/{repo_name}:{version_num}` - 如果沒有加 `:{version_num}` 預設是 `:latest` - ex. - ![](https://hackmd.io/_uploads/S1Xd-kU_n.png) - `docker tag backend_node tommygood/node_server` 3. `docker push {dockerhub_account}/{repo_name}` - ex. `docker push tommygood/node_server` - ref - https://ithelp.ithome.com.tw/articles/10192824 - 補充 - k8s 的 image 如果沒有用到 publish 的 image 會有問題 - https://ithelp.ithome.com.tw/articles/10193944 - run vs cmd : cmd 是當 `docker run` 這個 image 會執行的命令(也就是已經建立完 image 時),run 是在建立 image 的時候會執行的命令 ## docker-compose - 多個 command ```yml= command: > sh -c "python manage.py wait_for_db && python manage.py migrate && python manage.py runserver 0.0.0.0:8000" ``` - ref - https://stackoverflow.com/questions/30063907/docker-compose-how-to-execute-multiple-commands - volumes - bind : host 的<b>相同</b>路徑檔案內容對應到 container 的<b>相同</b>路徑檔案內容 - volume : container 的檔案內容存到 host 的 docker area 當中(通常會在 `/var/local`) - ex. ```conf= volumes: - type: bind source: /var/mosquitto/mosquitto.conf target: /mosquitto/config/mosquitto.conf - type: bind source: /var/mosquitto/log/ target: /mosquitto/log/ - type: volume source: data target: /mosquitto/data/ ```