Linux3

Week1 0221

建立新的kernel

寫一個簡單的驅動程式

編譯一個kernel

查看linux版本
uname -r

-r 精簡內容
-a 完整資訊

[user@centos7-3 ~]$ uname -r
3.10.0-957.el7.x86_64
[user@centos7-3 ~]$ uname -a
Linux centos7-3 3.10.0-957.el7.x86_64 #1 SMP Thu Nov 8 23:39:32 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

升級核心

通常只有出現重大問題時才需要更新
kernel檔案下載 https://www.kernel.org/

下載 wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.148.tar.xz

解壓縮
tar xvJf linux-5.15.148.tar.xz

安裝工具與函式庫
yum install -y ncurses-devel make gcc bc bison flex elfutils-libelf-devel openssl-devel grub2

cd linux-5.15.148

拷貝 目前核心的配置檔 到 新的核心的配置檔
cp -v /boot/config-3.10.0-957.el7.x86_64 .config

使用uname -r 查看核心

開啟或關閉 核心功能
make menuconfig

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

選項 * 代表直接加入核心, M 是模組化設計(可加載), 空白則是 不加載

核心功能模組化
把 功能 加入核心會使得核心的耗能(資源、記憶體)越來越大,即使沒有使用這些功能
因此 有需要特定功能才加入到核心(擴充)

如果報錯:GCC版本太舊

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

scl enable devtoolset-7 bash

如果出現

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

則是需要把視窗拉大 (視窗放不下GUI)


編譯

make bzImage
make modules
make
make modules_install
make install
grub2-mkconfig -o /boot/grub2/grub.cfg

完成後重新啟動 並選擇新的核心

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

uname -r 查看核心版本

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

可能出現的問題

make bzImage 報錯

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

sudo yum install openssl-devel

make bzImage 報錯

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

sudo yum install elfutils-libelf-devel


kernel 內部元素

模組: Process、Memory、File System、Device Control、Network

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

OS(x86)分成以下3層:

user space
> 包含app、lib
使用ring3模式(權限較低 出錯時危害性較低)

-------------
kernel space
> 包含 process management(行程的創建 運行 睡眠 中斷處理等...)
> 記憶體管理
使用ring0模式(權限較高 出錯時危害性較高)

-------------
HW

user space 切換到 kernel space 的時機

  1. 函式呼叫(system call)
  2. interupt

linux中存在虛擬的(邏輯的)檔案系統 vfs (virtual file system)

一般的系統都會與一個partition(磁碟分割區)對應
不同的檔案系統之間 讀/寫 的實作上不一定相同, 因此不同的檔案系統之間的操作 需要考慮檔案系統的類型或檔案格式
但vfs不需要, vfs不針對磁碟分割區(將多個不同的磁碟分割區封裝在一起), 因此透過vfs可以跨磁碟分割區讀寫


模組相關命令

列出目前載入核心的模組

lsmod

移除網路卡驅動程式

rmmod e1000
可以用ifconfig檢查是否生效

載入網路卡驅動程式網路卡驅動程式網路卡驅動程式網路卡驅動程式

  1. 先執行 updatedb
  2. 搜尋e1000.ko (網卡driver, ko是kernel module)
    locate e1000.ko
/home/user/Desktop/linux-5.15.148/drivers/net/ethernet/intel/e1000/.e1000.ko.cmd
/home/user/Desktop/linux-5.15.148/drivers/net/ethernet/intel/e1000/e1000.ko
/usr/lib/modules/3.10.0-1160.90.1.el7.x86_64/kernel/drivers/net/ethernet/intel/e1000/e1000.ko.xz
/usr/lib/modules/3.10.0-957.el7.x86_64/kernel/drivers/net/ethernet/intel/e1000/e1000.ko.xz
  1. insmod /usr/lib/modules/3.10.0-1160.90.1.el7.x86_64/kernel/drivers/net/ethernet/intel/e1000/e1000.ko.xz

Week2 0228 (放假)

Week3 0306

進階的SSH

使用帳號密碼的登入方式 可能被暴力破解

破解情境
機器A(192.168.245.144) 啟用SSH伺服器
機器B(192.168.245.154) 嘗試破解機器A

B機器 操作:

  1. 安裝nmap

sudo yum install nmap

  1. 掃描A開啟的port

nmap -sS -P0 -sV 192.168.245.0/24

[user@centos7-3 ~]$ sudo nmap -sS -P0 -sV 192.168.245.0/24

Starting Nmap 6.40 ( http://nmap.org ) at 2024-03-06 10:17 CST
Nmap scan report for 192.168.245.1
Host is up (0.00031s latency).
Not shown: 990 filtered ports
PORT     STATE SERVICE         VERSION
22/tcp   open  ssh?
80/tcp   open  http?
135/tcp  open  msrpc           Microsoft Windows RPC
139/tcp  open  netbios-ssn
445/tcp  open  microsoft-ds?
902/tcp  open  ssl/vmware-auth VMware Authentication Daemon 1.10 (Uses VNC, SOAP)
912/tcp  open  vmware-auth     VMware Authentication Daemon 1.0 (Uses VNC, SOAP)
2179/tcp open  vmrdp?
2869/tcp open  http            Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
8080/tcp open  http-proxy?
MAC Address: 00:50:56:C0:00:08 (VMware)
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

Nmap scan report for 192.168.245.2
Host is up (0.00024s latency).
Not shown: 999 closed ports
PORT   STATE SERVICE VERSION
53/tcp open  domain  dnsmasq 2.78
MAC Address: 00:50:56:FB:3F:E2 (VMware)

Nmap scan report for 192.168.245.144
Host is up (0.00036s latency).
Not shown: 998 closed ports
PORT    STATE SERVICE VERSION
22/tcp  open  ssh     OpenSSH 7.4 (protocol 2.0)
111/tcp open  rpcbind 2-4 (RPC #100000)
MAC Address: 00:0C:29:EA:DE:A8 (VMware)

Nmap scan report for 192.168.245.254
Host is up (-0.10s latency).
All 1000 scanned ports on 192.168.245.254 are filtered
MAC Address: 00:50:56:E1:56:FA (VMware)

Nmap scan report for 192.168.245.154
Host is up (0.0000020s latency).
Not shown: 998 closed ports
PORT    STATE SERVICE VERSION
22/tcp  open  ssh     OpenSSH 7.4 (protocol 2.0)
111/tcp open  rpcbind 2-4 (RPC #100000)

Service detection performed. Please report any incorrect results at http://nmap.org/submit/ .
Nmap done: 256 IP addresses (5 hosts up) scanned in 391.41 seconds

掃描結果包含了主機的狀態(up) 對應埠號的狀態(open)與版本(OpenSSH 7.4)

image

尋找對應SSH版本的漏洞

暴力破解 參考
安裝

wget https://github.com/vanhauser-thc/thc-hydra/archive/master.zip
yum -y install gcc libssh-devel openssl-devel
yum install -y unzip zip
unzip master.zip
cd thc-hydra-master/
./configure
make &&make install

建立 帳號檔案 與 密碼檔案
image

密碼檔下載

hydra -L user.txt -P password.txt 192.168.245.144 ssh

指令不生效 目前不確定原因 可以改用kali試試看

可能的解法


無密碼登入

step 0. 服務端上關閉密碼登入

vim /etc/ssh/sshd_config
image
設定 PasswordAuthentication no

step1. 在客戶端上執行 ssh-keygen

image
產生 新的公鑰(id_rsa.pub)、私鑰(id_rsa) (位置在~/.ssh/下)

step2. 在客戶端上執行 ssh-copy-id root@服務端IP

將公鑰複製給服務端(重啟sshd) 便可直接登入服務端 不須密碼


開啟PuTTYgen

螢幕擷取畫面 2024-06-13 124241

開啟後點擊Generate 後不斷移動滑鼠以生成隨機密鑰

image

將public key內容存放到 服務端的~/.ssh/authoried_keys

登入操作
image
image


寫一個簡單的Linux Driver

ref

配置

su
cd ~
mkdir test-driver
cd test-driver
mkdir hello
cd hello
vim hello.c

hello.c

/* hello.c */
#include <linux/init.h>
#include <linux/module.h>

MODULE_DESCRIPTION("GPL"); //模組描述
MODULE_LICENSE("GPL"); //模組授權

static int example_init(void) {
    printk(KERN_INFO "Hello world !\n"); // 功能同printf 但可以設定打印內容的層級(目前層級是INFO)
    return 0;
}

static void example_exit(void) {
    printk("<1>EXAMPLE: exit\n");
}

module_init(example_init);
// 模作被加載時 呼叫  inmod hello.ko

module_exit(example_exit);
// 離開時 呼叫  rmmod hello

Linux核心程式的特點

不使用main()
影響整個OS
編譯後副檔名是.ko
需要確定核心版本是否相符(uname -r)

Linux應用層程式
C語言程式碼的進入點是main()
只對該程式有影響

Makefile

#
# Makefile by appleboy
#
obj-m     += hello.o
KVERSION := $(shell uname -r)

all:
        $(MAKE) -C /lib/modules/$(KVERSION)/build M=$(PWD) modules
        
clean:

        $(MAKE) -C /lib/modules/$(KVERSION)/build M=$(PWD) clean

切換GCC版本scl enable devtoolset-8 bash

執行make

可用 dmesg 查看log
image

加載模組 ismod hello.ko

移除模組 rmmod hello


Week4 0313

ssh 無密碼登入(使用金鑰)

Client (192.168.245.144)
Server (192.168.245.145)

Client

  1. 重新設置~/.ssh

image
chmod 700 .ssh 權限須為700

  1. 生成金鑰

ssh-keygen -t rsa -b 4096
-t: 加密金鑰演算法
-b: 長度

image
密碼 123456
image

  1. Client將公鑰傳送給Server
    scp ./id_rsa.pub user@192.168.245.145:~/.ssh

  2. Server設置
    新增keycat id_rsa.pub >> authorized_keys
    設置authorized_keys權限 chmod 600 authorized_keys

  3. Client就可以無密碼登入Server了
    ssh -i 私鑰位置 user@serverIP


網頁伺服器延伸模組-WebDAV

WebDAV (Web-based Distributed Authoring and Versioning) Ref

使用網站空間作為磁碟

編輯配置檔
vim /etc/httpd/conf.d/webdav.conf
image

權限設置 chmod -R 755 /var/www/html
chown -R apache:apache /var/www/html
重啟 systemctl restart httpd

在 Windows上開啟
image
image
便可以共用雲端儲存空間


command Linux三劍客 awk/grep/sed

sed (steam editor)

read file line by line

-e 編輯模式 (顯示出修改後的內容 原檔案不變)
若要修改檔案 使用參數 -i

參數1 s: 取代
參數2 match
參數3 (生效範圍) g: 全域 若改成1便只取代第1個match('s/word1/word2/1' 預設是1 可省略)

image

image

同時進行2種操作
image

參數3 i ignore(不分大小寫), 不加i區分大小寫 其他command也適用
image

指定範圍
從第3行後才修改
image

修改 4~7 行
image

使用regex指定範圍

regex /^[^#]/ 表示 除了#開頭的行 以外
/^[] 除了以外
^# 以#為開頭
$為結尾

sed -e '/^[^#]/s/word1/word2/g' input
image

支援regex的grep command: egrep

cat input | egrep "[#]"
image

grep的參數 -v 表示 排除
cat input | egrep -v "^$" 排除空白行

image

#word2word2word1
#word2word2word2

sed -e '/[^#]word1$/s/word2/word4/g' input

把 以word1為結尾的行 中的 word2改成word4
image

進階用法
image
分割線/也可以使用#

.*匹配 任意字元
& 匹配*匹配到的任意字元
U uppercase L lowercase

image

把/etc/selinux/config中的SELINUX=desabled改成SELINUX-enforce
image

使用命令自動關閉SELinux
image

sed 常用指令 ref
a (新增)
c (替換)
d (刪除)
i (插入)
p (列印)
s (取代)

Week5 0320

通配符(WildCard) ref

作用:匹配檔案的名稱

? 匹配任意字符
* 匹配任意長度的任意字符
[] 匹配範圍 a-z 或 0-9

image

練習範例

ls a[[:upper:]][[:upper:]]
ls a[[:upper:]][[:lower:]]
ls a[[:upper:]]
ls a[1-9]
ls a[^1-9] ^表示 非

image

正則表達式 (Regex) ref

作用:匹配檔案的內容

^word 以word為開頭
word$ 以word為結尾
. 匹配1任意字符
.* 匹配多個(包含0、1、2)任意字符

grep -n 顯示行號
grep 參數可以直接使用regex

顯示系統帳號
grep nologin$ /etc/passwd | awk -F: '{print$1}'

image

-F指定分割的符號(這邊設為:, 預設是空白 或TAB )

image

匹配[opt]中的其中一個 (ro rp rt)
image

() 用於分組,允許你將多個字符作為一個單位進行操作,還能夠提取匹配的子字符串。
ex: (abc)+ 可以匹配 abc、abcabc、abcabcabc

| 用於表示"or"。
a|b 可以匹配 a 或 b
(abc|def) 可以匹配 abc 或 def

\ 用於轉義字符,使其具有字面意義,或者用於表示特定的字符類型(如數字、字母等)。

\. 可以匹配字符 .
\d 可以匹配任意數字,相當於 [0-9]
\w 可以匹配任意字母或數字,相當於 [a-zA-Z0-9_]

sed 參考

echo "123abc" | sed -r "s#(^.)(.)(.*)#\2\1\3#"

image
s#(^.)(.)(.*)#\2\1\3# 是一個替換命令:
s:表示替換操作。
#:是分隔符,可以使用 / 或其他字符。
(^.)(.)(.*):是正則表達式。
^. 匹配字符串的第一個字符。
. 匹配接下來的第二個字符。
.* 匹配剩餘的所有字符。
\2\1\3:這是替換部分。
\2 是第二個匹配組,即第二個字符。
\1 是第一個匹配組,即第一個字符。
\3 是第三個匹配組,即剩餘的字符。

image
-B: 顯示符合行之前的指定行數。
-A: 顯示符合行之後的指定行數。


image

/模式/p: 列印匹配模式的行。
s/模式/替換/: 將模式替換為指定的內容。

image

image

將 test 插入到 demo 文件的第一行之前。

image

將 demo 文件的第二行替換為 Hello

awk

awk -F: '{print $1,$3}' /etc/passwd

image
image
-F:: 設置字段分隔符(Field Separator)為冒號
'{print $1,$3}': print $1,$3印出第一字段($1)和第三字段($3)
$0 是全部

awk -F: '{if($1 == "user") print $1,$3}' /etc/passwd

image
if($1 == "user"): 條件語句,檢查第一字段(用戶名)是否等於 "user"。
print $1,$3: 如果條件為真,則打印第一字段(用戶名)和第三字段(用戶 ID),中間以空格分隔。
可以看到 user 用戶的用戶名和對應的用戶 ID

awk 也支援 ||&&
awk -F: '{if($1 == "user" || $1 == "root") print $1,$3}' /etc/passwd

root 0
user 1000

使用 NF(Number of Field), NR(Number of Record) 可顯示 匹配的 欄數 行數
awk -F: '{if($1 == "user" || $1 == "root") print $1,$3,NF,NR}' /etc/passwd

root 0 7 1
user 1000 7 37

Week6 0327

Docker

虛擬化技術

重量級 VMware, VirtualBox
輕量級 Docker

image

左半是 light 使用namespace與cgroups技術將不同的虛擬機 "隔離"
右半是 heavy Hypervisor 類似於 VMware、Virtualbox

namespace 是 Linux 核心技術,用於隔離系統資源,從而使一組進程可以看到另一組進程不可見的資源。這種隔離是實現容器技術的基礎。Docker 使用多種類型的 namespaces 來實現容器的隔離和安全性。

network namespace

Network Namespace 是一種 namespaces,用於隔離網絡資源。每個 Network Namespace 擁有自己的網絡設備、IP 地址、路由表、防火牆規則等。
每個 Docker 容器運行在自己的 Network Namespace 中,這使得容器之間的網絡環境完全隔離。通過這種方式,可以為每個容器分配獨立的網絡配置,從而避免相互干擾。

PID namespace

PID (Process ID) Namespace 是用於隔離進程 ID 空間的 namespaces。每個 PID Namespace 擁有自己獨立的進程樹,這意味著在不同的 PID Namespace 中,相同的進程 ID 可能代表不同的進程。
當一個容器啟動時,它運行在自己的 PID Namespace 中。這使得容器中的進程 ID 與宿主系統和其他容器中的進程 ID 相互隔離。這種隔離提高了安全性,並且容器內的進程看不到宿主系統或其他容器中的進程。

PID 1 systemd

在 Linux 系統中,PID 1 是系統啟動後運行的第一個進程,通常是 init 系統,如 systemd

install Docker

  1. rpm -qa | grep docker
 sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine

啟動 Docker 服務 systemctl start docker

查看版本 docker --version
測試 sudo docker run hello-world

image

列出所有映像(images) sudo docker images

image

列出運行中的容器(running containers) docker ps
列出所有容器(all containers):docker ps -a

容器的狀態
Up (運行中):容器目前正在運行。
Exited (已停止):容器已經停止運行,但仍然存在。
Paused (暫停):容器暫停運行,可以使用 docker unpause 命令來恢復運行。
Restarting (重啟中):容器正在重新啟動。
Dead (僵屍):容器已經停止,但 Docker 無法自動清理它。
Created (已創建):容器已經創建但尚未啟動。
Removing (移除中):容器正在被刪除,但尚未完全清理。
image
Exited

刪除容器 sudo docker rm 名稱或ID
image

可以一次刪除多個
image

一次刪除所有容器 sudo docker rm -rf `sudo docker ps -qa`
image

鏡像名稱的規則

repo/userName/imageName:tag

repo 是鏡像的位置 若沒寫 表示官方(dockerhub)
userName 若沒寫 表示官方(dockerhub), ex: Tom, mary, peter
tag 版本資訊 若沒寫 表示lasted(最新版)
例如 ``

aufs 進階多層統一檔案系統
advanced multi-layered unification filesystem

是一種用於 Linux 的文件系統,主要用於容器化技術,特別是 Docker
AUFS 允許將多個文件系統層(Layers)統一到單一的虛擬文件系統中。這對於容器技術特別有用,因為容器通常使用基於鏡像的層次結構來快速部署和修改應用程序環境。

以下是 AUFS 的一些特點和運作原理:

  1. 多層支持:AUFS 允許將多個只讀層(例如基礎映像)和一個可讀寫層(容器內的變更)合併成單個文件系統。這使得容器可以快速地從現有的映像層構建和運行。

  2. Copy-on-Write (COW):AUFS 使用了Copy-on-Write技術,這意味著當容器中的進程修改了文件時,AUFS 會在需要時進行文件的複製和修改,以保持原始層的完整性。

  3. 性能和效率:AUFS 通常被認為是一種性能良好且效率高的存儲驅動程序,因為它可以有效地管理多個層並支持快速的容器操作。

  4. 限制和兼容性:雖然 AUFS 是一個強大的文件系統,但它有時會受到 Linux 內核版本和特定操作系統配置的限制,這可能會影響到其在各種環境中的兼容性和使用。


因此需要更動鏡像時只能在最上層新增一層並修改 不能更動原有的層 並且如果想將修改後的層打包起來需要將所有的層打包成新的image

顯示 Docker 系統的詳細信息和配置。

sudo docker info
Client: Docker Engine - Community
 Version:    26.0.0
 Context:    default
 Debug Mode: false
 Plugins:
  buildx: Docker Buildx (Docker Inc.)
    Version:  v0.13.1
    Path:     /usr/libexec/docker/cli-plugins/docker-buildx
  compose: Docker Compose (Docker Inc.)
    Version:  v2.25.0
    Path:     /usr/libexec/docker/cli-plugins/docker-compose

Server:
 Containers: 0
  Running: 0
  Paused: 0
  Stopped: 0
 Images: 1
 Server Version: 26.0.0
 Storage Driver: overlay2
  Backing Filesystem: xfs
  Supports d_type: true
  Using metacopy: false
  Native Overlay Diff: true
  userxattr: false
 Logging Driver: json-file
 Cgroup Driver: cgroupfs
 Cgroup Version: 1
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local splunk syslog
 Swarm: inactive
 Runtimes: io.containerd.runc.v2 runc
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: ae07eda36dd25f8a1b98dfbf587313b99c0190bb
 runc version: v1.1.12-0-g51d5e94
 init version: de40ad0
 Security Options:
  seccomp
   Profile: builtin
 Kernel Version: 5.15.148
 Operating System: CentOS Linux 7 (Core)
 OSType: linux
 Architecture: x86_64
 CPUs: 1
 Total Memory: 3.797GiB
 Name: centos7-3
 ID: 7786a97e-565a-4582-821b-96cfdabce0fd
 Docker Root Dir: /var/lib/docker
 Debug Mode: false
 Experimental: false
 Insecure Registries:
  127.0.0.0/8
 Live Restore Enabled: false

這個命令通常用於檢查 Docker 守護進程的狀態、版本信息、容器和映像數量、存儲驅動程序的配置、網絡配置等。

sudo docker run -it name=centos2 centos:centos7 /bin/bash

image

  • sudo: 表示使用超級用戶權限運行 Docker 命令。
  • docker run: 啟動一個新的容器。
  • -it: 這兩個選項合併在一起,分別代表交互式(interactive)和終端(tty)。這兩個選項一般都一起使用,使得我們可以與容器內的 shell 進行交互。
  • --name=centos2: 為容器指定一個名稱 centos2,這樣我們可以使用這個名稱來引用或停止容器。
  • centos:centos7: 指定要運行的映像。這裡使用的是 CentOS 7 的官方映像 centos:centos7
  • /bin/bash: 指定容器內要運行的命令,這裡是啟動 Bash shell,讓我們可以在容器內進行交互操作。

啟動已經停止的容器 docker start

image

在運行中的容器內執行命令docker exec -it
image

docker exec [OPTIONS] CONTAINER COMMAND [ARG]

OPTIONS:一些,例如 -it 可以指定以交互式方式運行命令並且連接到容器的終端。
CONTAINER:要執行命令的容器的名稱或ID。
COMMAND:要在容器內執行的命令。
ARG:命令的參數。

離開容器

image

Ctrl pq

sudo docker exec -it 3d4 /bin/bash

image
在容器中新增的檔案會隨則容器被刪除 除非產生新的映象

sudo docker commit 942 centos:new 產生新的映象 docker commit ref
image


Week7 0410

下載image

docker pull [image_name]

查看image

docker images

建立Container(執行)

docker run
互動 docker run -it
背景 docker run -d
指定port docker run -p 例如:docker run -p 8080:80 (從host連線到docker中時 為把host的8080映射到docker的80)
指定空間(volumn)的對應(類似掛載資料夾) docker run -v 例如: docker run -v /mydata:/docker-data (把host的mydata 跟 docker的docker-data 資料夾同步)
傳送系統環境變量到docker docker run -e (例如傳送mysql的帳號密碼)
image
當容器使用結束時自動刪除而不是保持離開狀態exited 使用 --rm
開機時自動建立container 使用--restart

產生新的image docker commit

刪除容器 sudo docker rm -f `sudo docker ps -aq`

image

image

docker httpd

mkdir /mydata -p
cd /mydata
sudo docker pull httpd

執行web server
sudo docker run -d name www1 -p 8080:80 -v /mydata:/usr/local/apache2/htdocs/ httpd

此web server的家目錄位置 /usr/local apache2/htdocs
不是 /var/www/html

vim /mydata/hi.htm

hi

image

gcc

docker run -it --name testgcc --rm -v /mygcc:/mygcc gcc /bin/bash (容器端會自動創建/mygcc)

image

python

image

Dockerfile

使用Dockerfile建立image

FROM centos:centos7
RUN yum -y install httpd
EXPOSE 80
ADD index.html /var/www/html/

image

docker build -t centos7:web .

-t : tag
. 是當前目錄(這樣才會指定到Dockerfile)

docker run -d -p 8088:80 centos7:web /usr/sbin/apachectl -DFOREGROUND

image

image


進階內容

image

指令的串接
image

image

[常用]
CMD 指定容器创建时的默认命令。(可以被覆盖, 如果使用docker run -d -p 8088:80 centos7:web2 /bin/bashCMD ["/usr/sbin/apachectl", "-DFOREGROUND"]將不會生效, CMD會被/bin/bahs覆蓋)
ENTRYPOINT 设置容器创建时的主要命令。(不可被覆盖)
image

ADD和COPY類似 但ADD會自動解壓縮

Week8 0417

Docker 備份

  1. 手動

docker save

docker save hello-world:latest > hello.tar

將tar包傳給其他用戶

scp ./hello.tar 192.168.245.149:/tmp/hello.tar


docker load

docker load < /tmhello.tar

image

  1. 上傳Docker Hub

情境

image

docker commit:產生新的鏡像, docker tag:給鏡像別名

docker pull busybox

docker run -it rm name test2 busybox /bin/sh
到tmp下 新增一些檔案

建立新的鏡像

docker commit test2 GuangJhe/mybzbox:0.1

建立鏡像的別名

docker tag busybox:latest mybzbox:latest

image

登入Docker Hub

docker login

上傳Docker Hub

docker push guangjhe/mybzbox:0.1

image

從Docker Hub取得靜像

docker pull
image


附載均衡

情境圖
image

install HAProxy
sudo yum install haproxy openssl-devel -y

systemctl start haproxy

vim /etc/haproxy/haproxy.cfg

image

defaults
  mode http
  timeout client 10s
  timeout connect 5s
  timeout server 10s
  timeout http-request 10s

frontend myfrontend
  bind 0.0.0.0:8080
  default_backend myservers

backend myservers
  balance roundrobin
  server server1 192.168.245.144:8001
  server server2 192.168.245.144:8002
  server server3 192.168.245.144:8003
  server server4 192.168.245.144:8004
  server server5 192.168.245.144:8005

curl http://127.0.0.1:8080

每次請求都會從5台機器中選擇一台回復

用預設的docker0 brdge網路,docker間只能用ip互聯
如果自己創造的bridge網路,docker間通訊可以用ip或name互聯

Week9 0424

Docker四種網路模式(Bridge, Host, Container, None)

  1. Bridge 網路模式

Bridge 網路模式是 Docker 的默認網路模式。當你啟動一個新的容器而不指定特定的網路模式時,Docker 會自動將該容器連接到一個名為 bridge 的虛擬網路。
Bridge 網路的特點:
每個容器都有一個獨立的 IP 地址。
容器之間可以通過 IP 地址或容器名進行通訊。
容器與宿主機之間可以通過橋接網路進行通訊。
預設情況下,容器之間無法直接通過宿主機網路進行通訊,需要配置端口映射。
使用場景:
適用於需要容器之間互相通訊的應用場景。
適合小規模應用部署,提供基礎的網路隔離。

  1. Host 網路模式

在 Host 網路模式下,容器將直接使用宿主機的網路堆疊,繞過 Docker 的虛擬網路層。
Host 網路的特點:
容器與宿主機共享相同的網路名稱空間。
容器的網路配置(如 IP 地址、端口)與宿主機相同。
網路性能最佳,因為沒有網路虛擬化的開銷。
使用場景:
適用於需要高性能網路的應用。
適合需要直接訪問宿主機網路資源的容器,如監控工具、網路服務。

  1. Container 網路模式

在 Container 網路模式下,新的容器會與指定的已有容器共享網路名稱空間。這意味著兩個容器之間可以直接共享網路配置,如 IP 地址和端口。
Container 網路的特點:
多個容器共享相同的網路名稱空間。
容器之間可以直接通過內部網路進行通信,而不需要端口映射。
常用於多容器應用中,需要高度協同工作的容器之間。
使用場景:
適用於需要密切協作的多容器應用,例如微服務架構中的不同服務容器。
簡化容器之間的網路配置和通信。

  1. None 網路模式

None 網路模式是一種完全不配置網路的模式。在此模式下,容器啟動後不會分配任何網路接口或 IP 地址。
None 網路的特點:
容器沒有任何網路配置,完全孤立於網路之外。
容器內部的應用無法與其他容器或外部網路進行通信。
使用場景:
適用於不需要網路功能的應用或測試環境。
適合需要完全網路隔離的安全性場景。


列出 Docker 中所有網絡 docker network ls

安裝Docker-compose
curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose && chmod +x /usr/local/bin/docker-compose && docker-compose --version

架設MySQL
docker run -itd name mydb -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 network mybr mysql:5.7.24

執行
docker exec -it mydb bash

登入資料庫
mysql -uroot -p123456

/* 顯示目前有的資料庫 */
show databases;   
/* 創建資料庫 */
create database testdb;   
/*  使用資料庫 */
use testdb;  
/* 創建資料表 */
create table addrbook(name varchar(50) not null, phone char(10));
/* 加入資料 */
insert into addrbook(name, phone) values ("tom", "0912123456");
insert into addrbook(name, phone) values ("mary", "0912123567");
/* 選擇資料 */
select name,phone from addrbook;
/* 更新資料 */
update addrbook set phone="0987465123";

image

php

<?php
$servername="mydb";
$username="root";    
$password="123456";
$dbname="testdb";

$conn = new mysqli($servername, $username, $password, $dbname);

if($conn->connect_error){
    die("connection failed: " . $conn->connect_error);
}
else{
    echo "connect OK!" . "<br>";
}

$sql="select name,phone from addrbook";
$result=$conn->query($sql);

if($result->num_rows>0){
    while($row=$result->fetch_assoc()){
        echo "name: " . $row["name"] . "\tphone: " . $row["phone"] . "<br>";
    }
} else {
    echo "0 record";
}
?>
    

image

docker run -d -p 8080:8080 name my-apache-php-app network mybr -v "/root/test-docker/php-code":/var/www/html php:7.2-apache

若出現php:7.2-apache 版本與sql不符 可以改成radys/php-apache:7.4
sudo docker run -d -p 8080:80 name my-apache-php-app network mybr -v "/home/user/testdocker/php-code":/var/www/html radys/php-apache:7.4


Docker Volume

一種用於數據持久化的機制。它允許容器之間共享數據,並在容器刪除後依然保留數據。Volume 可以儲存在宿主機上,也可以使用外部存儲系統。

創建 Volume
docker volume create --name my_volume

查看 Volume
docker volume ls
使用 docker volume inspect 可以查看特定 Volume 的詳細信息。

在運行容器時,可以使用 -v--mount 選項來將 Volume 掛載到容器中。

docker run -d -v my_volume:/app/data my_image
docker run -d --mount source=my_volume,target=/app/data my_image

volume的應用

named volume
image

Named Volume

定義

Named Volume 是由 Docker 自動管理的卷。當你創建一個 Named Volume 時,Docker 會在宿主機上的預設位置創建一個目錄來存放這個卷的數據。你不需要知道這個目錄的具體位置,Docker 會幫你處理。

優點

易於使用:不需要指定宿主機上的具體路徑,Docker 自動管理。
跨平台一致性:在不同的平台(如 Windows 和 Linux)上,使用方式一致。
數據隔離:每個 Named Volume 都有自己獨立的存儲空間,避免了數據衝突。

創建 Named Volume:

docker volume create my_named_volume

刪除 Volume:

docker volume rm my_named_volume

Host Volume

定義

Host Volume 是將宿主機上的一個具體目錄掛載到容器中的一個目錄。這意味著容器可以直接訪問和使用宿主機上的文件系統。這種方式允許你更靈活地管理數據,因為你可以指定宿主機上的任何路徑。

優點

靈活性高:可以指定宿主機上的任意路徑,方便與宿主機上的其他應用共享數據。
直接訪問:容器內的應用可以直接讀寫宿主機上的數據,適合開發和測試環境。

使用方法

docker run -d name my_container -v /path/on/host:/app/data my_image
或者使用 mount 參數:
docker run -d name my_container mount type=bind,source=/path/on/host,target=/app/data my_image

注意事項

安全性:因為容器可以直接訪問宿主機上的文件,可能會帶來安全風險。
依賴性:容器的數據依賴於宿主機的文件系統,可能會導致數據的可移植性降低。


Network Namespace

Network Namespace 是 Linux 中的一種網絡隔離機制。每個 Network Namespace 都擁有自己獨立的網絡設備、IP 地址、路由表和防火牆規則。這允許不同的應用程序或服務在同一台主機上運行,而不會互相干擾。

使用 Network Namespace 的一個常見場景是容器化技術,如 Docker,它利用 Network Namespace 為每個容器提供獨立的網絡環境。

ip 命令

創建 Network Namespace

sudo ip netns add Container
image

查看 Network Namespace

ip netns list

在 Network Namespace 中運行命令

sudo ip netns exec Container ip a

顯示該 Namespace 中的網絡接口訊息

ip addr show

刪除 Network Namespace

sudo ip netns del Container

配置 Network Namespace 的網絡

創建虛擬以太網對 (veth pair) sudo ip link add veth0 type veth peer name veth1
將一個接口移動到 Network Namespace sudo ip link set veth1 netns Container
配置接口和 IP 地址
在宿主機上配置 veth0:
sudo ip addr add 192.168.1.1/24 dev veth0
sudo ip link set veth0 up

在 Container Network Namespace 中配置 veth1:
sudo ip netns exec Container ip addr add 192.168.1.2/24 dev veth1
sudo ip netns exec Container ip link set veth1 up

配置路由
sudo ip route add 192.168.1.2/32 dev veth0

在 Container Network Namespace 中配置路由,使其能夠通過 veth1 接口訪問宿主機:
sudo ip netns exec Container ip route add default via 192.168.1.1

Week10 0501

建立一個機器學習服務的Docker

環境設置

  1. 安裝pip、sklearn

yum install python-pip
python -m pip install pip20.3.4
pip install sklearn

train_model.py

# coding: utf-8
import pickle
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn import tree

# simple demo for traing and saving model
iris=datasets.load_iris()
x=iris.data
y=iris.target

#labels for iris dataset
labels ={
  0: "setosa",
  1: "versicolor",
  2: "virginica"
}

x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=.25)
classifier=tree.DecisionTreeClassifier()
classifier.fit(x_train,y_train)
predictions=classifier.predict(x_test)

#export the model
model_name = 'model.pkl'
print("finished training and dump the model as {0}".format(model_name))
pickle.dump(classifier, open(model_name,'wb'))

image

pip install flask

flask default port : 5000

server.py

# coding: utf-8
import pickle

from flask import Flask, request, jsonify

app = Flask(__name__)

# Load the model
model = pickle.load(open('model.pkl', 'rb'))
labels = {
  0: "versicolor",
  1: "setosa",
  2: "virginica"
}

@app.route('/api', methods=['POST'])
def predict():
    # Get the data from the POST request.
    data = request.get_json(force = True)
    predict = model.predict(data['feature'])
    return jsonify(predict[0].tolist())

if __name__ == '__main__':
    app.run(debug = True, host = '0.0.0.0')

client.py

# coding: utf-8
import requests
# Change the value of experience that you want to test
url = 'http://127.0.0.1:5000/api'
feature = [[5.8, 2.0, 4.2, 3.2]]
labels ={
  0: "setosa",
  1: "versicolor",
  2: "virginica"
}

r = requests.post(url,json={'feature': feature})
print(labels[r.json()])

image


基礎image

docker pull nitincypher/docker-ubuntu-python-pip

Dockerfile

FROM nitincypher/docker-ubuntu-python-pip

COPY ./requirements.txt /app/requirements.txt

WORKDIR /app

RUN pip install -r requirements.txt

COPY server.py /app

COPY train_model.py /app

CMD python /app/train_model.py && python /app/server.py

requirements.txt

sklearn
flask

建立新的image

docker build -t iris:1.0 .

測試
image

docker run -itd name iris -p 5000:5000 iris:1.0
docker ps
python client.py

CI/CD (持續集成/持續部署)

git 初始化

git config global user.name "KimLinTW"
git config global user.email "linkim0914@gmail.com"
git init

git remote add origin https://gitlab.com/KimLinTW/iris2024.git

image

image

git push -uf origin master

image

下載gitlab-runner

curl -L output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64
chmod +x /usr/local/bin/gitlab-runner

useradd comment 'GitLab Runner' create-home gitlab-runner shell /bin/bash
usermod -aG docker gitlab-runner

image

/usr/local/bin/gitlab-runner install user=gitlab-runner working-directory=/home/gitlab-runner
/usr/local/bin/gitlab-runner start

image
ps -ef | grep gitlab-runner

image

image
gitlab-runner register
image

vim .gitlab-ci.yml

stages:
  - deploy

docker-deploy:
  stage: deploy
  script:
    - docker build -t iris .
    - if [ $(docker ps -aq --filter name=iris) ]; then docker rm -f iris; fi
    - docker run -d -p 5000:5000 --name iris iris
  tags:
    - centos2

tage需要一致

image

Week11 0508

[補充-背景執行]

test.sh

#!/usr/bin/bash

for i in {1..200}
do
    echo $i
    sleep 1
done

image

>log表示 將標準輸出導向到log(任意名稱的檔案) 2>&1表示將標準錯誤導向到標準輸出 &表示背景執行
使用 tail 可以追蹤輸出的紀錄 -f表示follow
但視窗關閉後程式(test.sh)會中斷,可以透過putty連線並 使用nohup ./test/sh >log 2>&1 &避免 關閉終端時工作中斷
image
使用putty重新連線,程式仍繼續執行

docker-compose

Docker Compose 是 Docker 的一個工具,用於定義和運行多容器的 Docker 應用。通過使用 Docker Compose,可以使用一個 YAML 文件來配置應用服務,並且可以用一條命令來啟動所有服務。

YAML

YAML (Yet Another Markup Language) 是一種簡單的數據序列化格式,常用於配置文件。它使用縮進來表示層次結構,易於人類閱讀。

在 Docker Compose 中,使用一個 docker-compose.yml 文件來定義多個服務。下面是一個示例:

version: '3.8'  # 指定 Docker Compose 文件的版本

services:  # 定義服務
  web:  # web 服務
    image: nginx:latest  # 使用的 Docker 映像
    ports:
      - "8080:80"  # 將宿主機的 8080 端口映射到容器的 80 端口
    volumes:
      - ./html:/usr/share/nginx/html  # 將宿主機的 ./html 目錄掛載到容器的 /usr/share/nginx/html 目錄
    networks:
      - webnet  # 指定服務所屬的網絡

  db:  # db 服務
    image: postgres:latest  # 使用的 Docker 映像
    environment:  # 環境變量
      POSTGRES_DB: exampledb  # 設置 PostgreSQL 數據庫名稱
      POSTGRES_USER: exampleuser  # 設置 PostgreSQL 用戶名
      POSTGRES_PASSWORD: examplepass  # 設置 PostgreSQL 用戶密碼
    volumes:
      - dbdata:/var/lib/postgresql/data  # 將名為 dbdata 的卷掛載到容器的 /var/lib/postgresql/data 目錄
    networks:
      - webnet  # 指定服務所屬的網絡

volumes:  # 定義卷
  dbdata:  # 定義名為 dbdata 的卷

networks:  # 定義網絡
  webnet:  # 定義名為 webnet 的網絡


下載docker compose

curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose && chmod +x /usr/local/bin/docker-compose && docker-compose --version

sudo yum install docker-compose-plugin

位置在/usr/local/bin/docker-compose

chmod +x docker-compose

使用root 安裝
curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose && chmod +x /usr/local/bin/docker-compose && docker-compose --version

基本命令

docker-compose up:創建並啟動所有服務。
docker-compose down:停止並刪除所有服務和網絡。
docker-compose build:構建或重新構建服務。
docker-compose ps:列出所有運行中的服務。
docker-compose stop : 停止由 docker-compose 管理的所有服務。這會停止但不會刪除容器。
docker-compose restart : 重啟由 docker-compose 管理的所有服務。這將先停止服務,然後重新啟動它們。
docker-compose rm : 刪除由 docker-compose 管理的所有停止的容器。這將刪除停止的容器,而不會刪除正在運行的容器。

範例test1

docker-compose.yml

services:
  app:
    image: hello-world

image

打印hello便結束 因此需要使用docker-compose ps -a查看 狀態

範例test2

Dockerfile

FROM alpine

RUN apk add --no-cache bash

CMD bash -c 'for((i=1;;i+=1)); do sleep 1 && "Counter: $i"; done' 

詳細說明:

for ((i=1;;i+=1)):這是一個無限循環的 for 迴圈,從 1 開始,每次增加 1。
do 和 done:定義了迴圈的開始和結束。
sleep 1:讓迴圈每次迭代時等待一秒鐘。
echo "Counter: $i":輸出計數器的值。

使用基礎鏡像alpine

docker-compose.yml

services:
  app:
    build:
      context: .

context: . 中的.代表Dockerfile

執行

  1. docker-compose build 產生鏡像
  2. docker-compose up -d 背景執行

image
image

顯示所有服務的日誌 `docker-compose logs

範例test3

改變映像預設執行的指令
docker-compose.yml

services:
  app:
    build:
      context: .
    image: counter
    command: >
      bash -c 'for((i=1;;i+=2)); do sleep 1 && echo "Counter: $$i"; done'

Dockerfile

FROM alpine

RUN apk add --no-cache bash

CMD bash -c 'for((i=1;;i+=1)); do sleep 1 && "Counter: $i"; done' 

docker-compose logs -f
-f 表示「跟踪」或「實時輸出」。它會持續監聽服務的日誌輸出,並且會顯示新的日誌消息。

範例test4

掛載外部檔案系統的目錄
docker-compose.yml

services:
  app:
    image: busybox
    volumes:
      - /path/to/src1:/path/to/dest1

volumes 定義了容器與主機之間的文件系統映射關係。在這個例子中,將本地主機中的 /path/to/src1 目錄掛載到容器內的 /path/to/dest1 目錄。
這種卷的掛載方式允許容器內的應用程序可以訪問主機上的特定目錄,並且對這些目錄的更改在主機和容器之間是共享的。

BusyBox

BusyBox 是一個開源的輕量級 Unix 工具集合,它被設計成在嵌入式系統中運行,佔用空間小且功能齊全。以下是 BusyBox 的一些主要特點和用途:
BusyBox 通常僅佔用幾百 KB 的空間,這使得它在嵌入式系統中非常受歡迎,因為它可以提供完整的 Unix 工具集合而不需要大量的存儲空間。
BusyBox 包含了許多常見的 Unix 工具,如 ls、grep、awk、sed、tar、sh 等,這些工具被整合在一個可執行文件中。
用於輕量級應用和調試:

範例test5

index.html

hello world

Dockerfile

FROM centos:centos7
RUN yum -y install httpd
EXPOSE 80
ADD index.heml /var/www/html/index.html
CMD ["/usr/sbin/apachectl","-DFOREGROUND"]

EXPOSE 80:將容器內部的 80 端口暴露出來,以便外部可以訪問。
ADD index.html /var/www/html/index.html:將主機上的 index.html 文件複製到容器內的 Apache 默認網站目錄 /var/www/html 中。
CMD ["/usr/sbin/apachectl", "-DFOREGROUND"]:設置容器啟動後的默認命令,啟動 Apache 並以前台運行。

docker-compose.yml

services:
  app:
    build:
      context: /
    ports:
      - "3000-3063:80"

ports:映射端口。
"3000-3063:80":將主機的 3000 至 3063 範圍的端口映射到容器的 80 端口,這樣可以通過 http://localhost:3000http://localhost:3063 來訪問服務。

直接執行 docker-compose up -d
curl 127.0.0.1:3000

hello world

docker-compose down

水平擴容(擴增相同機器的數量)
直接執行 docker-compose up -d scale app=5
在 Docker Compose 中擴展 app 服務到 5 個容器
image

垂直擴容(增加單台機器的能力 例如CPU、Memory)

範例test6 (flask+redis)

統計連線次數

app.py

from flask import Flask
import time
import redis

app = Flask(__name__)
cache = redis.Redis(host='redis', port=6379)

def get_hit_count():
  retries = 5
  while True:
    try:
      return cache.incr('hits')
    except redis.exceptions.ConnectionError as exc:
      if retries == 0:
        raise exc
    retries -= 1
    time.sleep(0.5)


@app.route('/')
def get_index():
  count = get_hit_count()
  return 'Yo!  你是第{}次瀏覽.'.format(count)

app.run(host='0.0.0.0', debug=True)

docker-compose.yml

services:
  web:
    build: .
    ports:
      - "5000:5000"
    volumes:
      - ./:/code/
    depends_on:
      - redis
  redis:
    image: "redis:alpine"

Dockerfile

FROM python:3.9
ADD ./ /code
WORKDIR /code
RUN pip install -r requirements.txt
CMD ["python", "app.py"]

requirements.txt

flask
redis

image

Week12 0515

補充 1panel

docker swarm

Docker Swarm 是 Docker 官方提供的容器编排和集群管理工具,用於管理和調度多個 Docker 容器的平台。它允許用戶將一組 Docker 主機(物理機器或虛擬機器)集成成一個虛擬容器超級電腦,這樣可以更輕鬆地部署和管理應用程序服務。

初始化

docker swarm init advertise-addr 192.168.245.145

增加工作節點(在其他vm執行)

docker swarm join token SWMTKN-1-2jzwrk7lzs54x2vpn7z2zi06qdlqs7bb9d5bh20z9psgn4kiz8-bago2i4wbmpslv1sb0kxxh4fc 192.168.245.145:2377
確認加入成功
docker node ls
image

檢查節點的 Swarm 狀態 docker node ls
離開 Swarm 集群 `docker swarm leave


圖形化頁面呈現swarm狀態

docker service create name=viz public=8888:8080/tcp constraint=node.role==manager mount=type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock dockersamples/visualizer
image

在docker swarm上建立一個叫做myweb鏡像(使用httpd)
docker service create name myweb httpd

image

列出所有在 Docker Swarm 中運行的服務 docker service ls
顯示特定服務(myweb)的所有任務(tasks)的狀態docker service ps myweb

image

調整服務副本數量

docker service scale myweb=3

調整 Docker Swarm 集群中指定服務的副本數量。這個命令允許你動態地增加或減少服務的運行副本,以應對不同的負載需求。

從排程中移除選項

docker node update availability drain 用於更改 Docker Swarm 集群中指定節點的可用性狀態。當一個節點的可用性被設置為 drain 時,該節點將不會接受新的任務,並且會試圖將現有的任務遷移到其他可用節點。
docker node update availability drain centos73
image

加入到排程選項中

docker node update availability active

使用drain會把原本在manager上的工作排到其他的節點,但重新再更新active,並不會主動移動已經創造的服務

在創建時預先指定副本數

docker service create name myweb replicas 3 http
-replicas 3: 指定該服務運行 3 個副本

提供對外服務

docker service update publish-add 8080:8- myweb

publish-add 8080:80: 添加一個端口映射,將宿主機的 8080 端口映射到容器的 80 端口。

Week12 0522

容錯(將鏡像的資料掛載到NFS)

機器1 設置NFS

sudo yum install nfs-utils
vim /etc/exports
/mydb/ IP/24(rw,sync,no_root_squash,no_all_squash)
/myphp/ IP/24(rw,sync,no_root_squash,no_all_squash)
sudo systemctl start rpcbind
sudo systemctl start nfs
確保掛載成功 showmount -e localhost

機器2、3

mount -t nfs 機器1IP:/mydb /mydb
mount -t nfs 機器1IP:/myphp /myphp

在 Docker Swarm 中,預設的網路是 overlay,這意味著容器之間的通訊主要透過 IP 進行,而不是透過容器的名稱。換句話說,容器不能直接使用其他容器的名稱來通訊,而是需要使用它們的 IP 地址。這是因為 overlay 網路是一種虛擬網路,跨多個 Docker 主機進行連接,容器的名稱解析僅限於各自的主機範圍內。

新增自訂的overlay網路

docker network create -d overlay mynet

image

部屬(任一機器)

docker service create name mydb network mynet mount type=bind,source=/mydb,target=/var/lib/mysql env MYSQL_ROOT_PASSWORD=123456 publish published=3306,target=3306 mysql
--mount type=bind,source=/mydb,target=/var/lib/mysql: 指定掛載一個綁定式掛載點,將主機上的 /mydb 目錄掛載到容器內的 /var/lib/mysql 目錄。這樣做的目的是持久化 MySQL 的數據。
--env MYSQL_ROOT_PASSWORD=123456: 設置一個環境變量 MYSQL_ROOT_PASSWORD,並設置其值為 123456。這個環境變量用於設置 MySQL 的 root 用戶的密碼。

docker exec -it [id] bash

mysql -uroot -p
建立資料庫(create database testdb)

移除服務 (docker service rm mydb)

重新啟動後 db仍然存在

image

在master node上
vim /myphp/test.php

<?php
$servername="mydb";
$username="root";
$password="123456";
$dbname="testsql";

$conn = new mysqli($servername, $username, $password, $dbname);

if($conn->connect_error){
	die("connecttion failed: " . $conn->connect_error);
}
else{
	echo "connect ok!" . "<br>";
}

$sql="select * from testtable";
$result=$conn->query($sql);

if($result->num_rows>0){
	while($row=$result->fetch_assoc()){
		echo "school: " . $row["school"] . "\tname: " . $row["name"] . "\tid: " . $row["id"] . "<br>";
	}
}else {
	echo "0 record";
}
?>

啟動php

docker service create name myphp network mynet mount type=bind,source=/myphp,target=/var/www/html publish published=8888,target=80 radys/php-apache:7.4
使用curl localhost/test.php請求測試
image

Week13 0529

Ansible

Ansible 是一個開源的自動化工具,用於配置管理、應用部署、任務自動化和 IT 服務編排。它主要用於管理和維護虛擬機(VM)、伺服器和雲基礎設施。Ansible 使用無代理的方式運行,這意味著它不需要在被管理的節點上安裝任何軟體,只需使用 SSH 連接即可。

VM的管理、維護
其他功能類似的軟體 puppet、chef、saltstack

Ansible 的兩種運行模式

  1. ad hoc模式 (命令式)

Ad Hoc 模式是指直接在命令行中執行 Ansible 命令,這種方式適合執行一次性的任務,例如檢查伺服器狀態、安裝軟體等。
ex:檢查所有伺服器的可達性 ansible all -m ping、在所有伺服器上安裝 httpd 套件ansible all -m yum -a "name=httpd state=present" -b、在指定伺服器上執行命令ansible webservers -a "/bin/echo hello"

  1. 腳本模式

腳本模式使用 YAML 語法來編寫 Playbook,這種方式適合執行複雜的任務和多步驟的操作。Playbook 可以重複運行,確保環境的一致性。


為了方便操作 先設定ssh無密碼登入

安裝軟體 sudo yum install -y ansible

設定權限sudo vim /etc/ansible/ansible.cfg

[defaults]
inventory     = /etc/ansible/hosts
ask_pass      = False

[privilege_escalation]
become=True
become_method=sudo
become_user=root
become_password=user
become_ask_pass=True

配置
sudo vim /etc/ansible/hosts

[server1]
192.168.254.145

[server2]
192.168.254.149

[servers]
192.168.254.145
192.168.254.149

測試

ansible server1 -m ping
ansible servers -m ping
ansible server2 -m ping

腳本範例-使用playbook

---
- hosts: server1
  tasks:
    - name: test ping 
      ping:

image

Week14 0605

在 server1 上執行 ls 命令,但只有在當前目錄中不存在名為 a 的文件或目錄時才會執行。
ansible server1 -m command -a "creates=a ls"

若 檔案 a 不存在 便執行 ls
若 檔案 a 存在 便不執行 ls
image

ansible server1 -m command -a "removes=b rm b"

若 檔案 b 存在 便刪除 b
跟creates相反

在其他機器上執行本地腳本a.sh

image

在其他機器上安裝、移除或檢查套件

ansible server1 -m shell -a "rpm -qa | grep httpd"
ansible server1 -m yum -a "name=httpd state=absent"
ansible server1 -m shell -a "rpm -qa | grep httpd"
ansible server1 -m yum -a "name=httpd state=present"
ansible server1 -m shell -a "rpm -qa | grep httpd"
image

遠端複製

模組: copy、template

copy模組
image

同時設定權限
image

file模組 也可以用來設定權限
image

service模組 功能類似systemctl
ansible server1 -m service -a "name=httpd state=started"
ansible server1 -m service -a "name=httpd state=stopped"
image

查看cpu memory配置
ansible server1 -m setup | grep cpu
ansible server1 -m setup | grep mem
image

template模組
jinja2格式 (hi.j2)

Hello "{{ dynamic_world }}"

在test33.yml中設定 hi.j2 的變數值= "World"

---
- hosts: server1
  gather_facts: no
  vars:
    dynamic_world: "World"
  tasks:
    - name: test template
      template:
        src: hi.j2
        dest: /tmp/hello_world.txt

image

Week15 0612

範例1

當特地事件觸發(notiy)時 執行特定命令(handlers)
ex: 當配置檔更動了便重啟
playbook.yml

- hosts: server1
  tasks:
    - name: install httpd server
      yum: name=httpd state=present

    - name: configure httpd server
      copy: src=./httpd.conf dest=/etc/httpd/conf/httpd.conf
      notify: restart httpd server

    - name: start httpd server
      service: name=httpd state=started enabled=yes

  handlers:
    - name: restart httpd server
      service: name=httpd state=restarted

image

notify:用於通知處理器在任務變更時執行。
handlers:定義處理器的行為,處理器只會在被通知時運行。這在需要在特定條件下執行的操作(如重啟服務)中特別有用。

範例2

變數的使用

playbook.yml

- hosts: server1
  vars:
    - app1: httpd
    - app2: vsftpd

  tasks:
    - name: install {{ app1 }} and {{ app2 }}
      yum:
        name:
          - "{{ app1 }}"
          - "{{ app2 }}"
        state: present

image

範例3

把變數設置在外部檔案(vars_public.yml)

playbook.yml

- hosts: server1
  vars_files: ./vars_public.yml

  tasks:
    - name: install {{ app1 }} and {{ app2 }}
      yum:
        name:
          - "{{ app1 }}"
          - "{{ app2 }}"
        state: present

vars_public.yml

app1: wget
app2: gedit

image

範例4

群組變數

./group_vars/server1

app1: httpd
app2: vsftpd

在 Ansible 中,群組變數是指為特定主機群組定義的變數。這些變數在 inventory 文件或專門的群組變數文件中定義,並且適用於該群組中的所有主機。群組變數有助於管理和配置大量主機時保持一致性和簡化配置過程。
名稱固定

playbook.yml

- hosts: server1
  tasks:
    - name: install {{ app1 }} and {{ app2 }}
      yum:
        name:
          - "{{ app1 }}"
          - "{{ app2 }}"
        state: present

image

範例5

主機變數

./host_vars/192.16879.114

app1: httpd
app2: vsftpd

./host_vars/192.16879.115

app1: wget
app2: curl

主機變數(Host Variables)是在 Ansible 中為單個主機定義的變數。這些變數可以在 inventory 文件中直接定義,也可以放在專門的主機變數文件中。使用主機變數可以針對特定主機進行配置,這在需要對某些主機進行特別配置時非常有用。
名稱固定

playbook.yml

- hosts: 192.168.79.114
  tasks:
    - name: install {{ app1 }} and {{ app2 }}
      yum:
        name:
          - "{{ app1 }}"
          - "{{ app2 }}"
        state: present

- hosts: 192.168.79.115
  tasks:
    - name: install {{ app1 }} and {{ app2 }}
      yum:
        name:
          - "{{ app1 }}"
          - "{{ app2 }}"
        state: present

image

範例9

配置 memory cache (根據主機的memory)

memcached.j2

PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="{{ ansible_memtotal_mb //2 }}"
OPTIONS=""

CACHESIZE="{{ ansible_memtotal_mb //2 }}"計算並設置memory大小 (CACHESIZE) 為目標主機總memory的一半(以 MB 為單位)。使用 ansible_memtotal_mb 變數來獲取目標主機的總memory。

playbook.yml

- hosts: server1
  tasks:
    - name: install memcached server
      yum: name=memcached state=present
    
    - name: configure memcached server
      template: src=./memcached.j2 dest=/etc/sysconfig/memcached
 
    - name: service memcached server
      service: name=memcached state=started enabled=yes

    - name: check memcached server
      shell: ps aux | grep memcached
      register: check_mem

    - name: debug memcached variables
      debug:
        msg: "{{ check_mem.stdout_lines }}"

image