環境資訊中心綜合外電;姜唯 編譯;林大利 審校
本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包”嚨底家”
※網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線
※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整
※小三通海運與一般國際貿易有何不同?
※小三通快遞通關作業有哪些?
摘錄自2018年9月21日蘋果日報美國洛杉磯報導
洛杉磯市議會周二(18日)通過議案,將立法禁止銷售皮草衣飾。議會全體投下贊成票,立場堅定;洛杉磯將成為美國禁售皮草的最大城市,可望為其他時尚重鎮帶來示範作用。
洛杉磯市議會以12比0的票數,一致贊成禁止商業皮草。立法機構負責草擬法規,由市議會審核,正式法規將在通過審議的兩年後生效。預計這類法規會為宗教目的、合法漁獵執照持有者另闢途徑,允許合法使用或生產動物皮草。
加州舊金山、西好萊塢、柏克萊都已限制皮草,但像洛杉磯這麼大規模的城市還是首例。提出此議案的議員科瑞茲(Paul Koretz)表示,洛杉磯是世界時尚之都,期許此舉能成為世界典範,紐約、芝加哥和邁阿密等大城可以跟進。
本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※想知道網站建置、網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計及後台網頁設計
※不管是台北網頁設計公司、台中網頁設計公司,全省皆有專員為您服務
※Google地圖已可更新顯示潭子電動車充電站設置地點!!
※小三通物流營運型態?
※快速運回,大陸空運推薦?
摘錄自2018年9月21日蘋果日報美國加州報導
美聯社報導,加州州長布朗(Jerry Brown)簽署通過法案,明年起禁止州內餐廳主動提供顧客塑膠吸管服務,首開全美先例。餐廳業者若不配合將先予以警告,兩次警告後開罰,每年最高300美元(約9,200台幣),由州內衛生人員負責不定時執行稽查。不過,此法僅適用於正式、有服務生點餐的餐廳,速食業者不再此限。儘管不是直接禁止,部分共和黨人仍批評這項新法「管太多」。
民主黨的布朗將環保議題列為優先施政考量。他指,每年大量塑膠垃圾流入海中,殺死鯨魚和魚類,污染最終進到民眾的食物和供水:「我們對一次性便利用具的迷戀,將招致災難性的後果。所有形式的塑膠製品,塑膠吸管、寶特瓶、包裝、塑膠袋等,都在使地球窒息。」
同天,布朗簽署通過另項法案,規定販售兒童餐的各級餐廳,都必須將菜單飲料預設為牛奶和開水。兩項法案皆從明年1月1日開始生效。
本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線
※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益
※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象
※台灣寄大陸海運貨物規則及重量限制?
※大陸寄台灣海運費用試算一覽表
摘錄自2018年9月22日蘋果日報美國加州報導
南加州人對今夏的記憶大概就是熱浪、野火、髒空氣。該地區空氣的臭氧含量連續87天超標,據《洛杉磯時報》報導,這創出至少20年來最長的紀錄。環保官員表示,日期長短不是判斷空污程度的指標,但這確實對健康有影響。
臭氧是導致氣喘和其他呼吸疾病發作的原因之一。加州空氣監測數據顯示,該州南部包含洛杉磯郡、橘郡、河濱郡等地,自6月19日至9月13日,空氣中臭氧含量都高於標準值70ppb;上周末雖略有緩和,但並未散退,本周又持續超標。
加州南岸空氣品質管理局(South Coast Air Quality Management District)表示,用連續日期數據衡量臭氧抑制的進展,並不恰當。今年的霧霾季比去年晚開始,目前為止,霧霾狀況沒有去年嚴重,臭氧含量最高值和「非常不健康」的日數都比較少。
去年臭氧超標的總日數為145天,前年為132天。該管理局無法確定最長的連續超標日紀錄,發言人表示,因為那不是美國環保局規定的空氣品質測量方式,所以沒追蹤。監管機構將空氣品質劣化歸咎於天氣變熱,使污染物質被光分解的速度加快;逆溫層較往年持久,污染物不易散開。
環保團體和監督機構都不認同此番解釋。南岸空氣品質委員會成員喬瑟夫盧(Joseph Lyou)表示,無論法律是否以此作為標準,長期空氣不良的趨勢都令人不安。環保團體譴責,官員應該可以有更多政策取締污染源,例如煉油廠或排放廢氣的「烏賊車」。
本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!
※網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!
※想知道最厲害的台北網頁設計公司推薦、台中網頁設計公司推薦專業設計師”嚨底家”!!
※大陸寄台灣空運注意事項
※大陸海運台灣交貨時間多久?
※避免吃悶虧無故遭抬價!台中搬家公司免費估價,有契約讓您安心有保障!
摘錄自2018年9月24日中央社報導
台灣、美國與菲律賓環境暨天然資源部合作舉辦的「第8屆國際電子廢棄物回收管理夥伴會議」(The 8th International E-waste Management Network Workshop)24日在菲律賓奎松市(Quezon City)Seda Vertis大酒店開幕,為期五天,來自全球5大洲的11個夥伴國家逾50位專家學者參與,交流各國電子廢棄物管理經驗。行政院環境保護署以資源回收基金補貼業者,以此建立回收處理體系的成功經驗,在這次會議中成為各國諮詢的焦點。
環保署表示,透過多年宣揚,現在已有馬來西亞參考台灣資源回收制度,推動家用電子廢棄物回收試辦計畫,隨後也宣布將參考台灣家用電子廢棄物的管理模式及制度,成立基金管理會,是台灣環保政策輸出國外的成功案例。
這場會議,目的在提升全球電子廢棄物回收處理環境無害化的管理能力,由台灣行政院環境保護署與美國環境保護署贊助。
本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※專營大陸空運台灣貨物推薦
※台灣空運大陸一條龍服務
1 apiVersion: v1 #必選,版本號,例如v1,版本號必須可以用 kubectl api-versions 查詢到 2 kind: Pod #必選,Pod 3 metadata: #必選,元數據 4 name: string #必選,Pod名稱,需符合RFC 1035規範 5 namespace: string #必選,Pod所屬的命名空間,默認為"default" 6 labels: #自定義標籤 7 - name: string #自定義標籤名字 8 annotations: #自定義註釋列表 9 - name: string 10 spec: #必選,Pod中容器的詳細定義 11 containers: #必選,Pod中容器列表 12 - name: string #必選,容器名稱,需符合RFC 1035規範 13 image: string #必選,容器的鏡像名稱 14 imagePullPolicy: [ Always|Never|IfNotPresent ] #獲取鏡像的策略,Alawys表示每次都嘗試下載鏡像,IfnotPresent表示優先使用本地鏡像,否則下載鏡像,Nerver表示僅使用本地鏡像 15 command: [string] #容器的啟動命令列表,如不指定,使用打包時使用的啟動命令 16 args: [string] #容器的啟動命令參數列表 17 workingDir: string #容器的工作目錄 18 volumeMounts: #掛載到容器內部的存儲卷配置 19 - name: string #引用pod定義的共享存儲卷的名稱,需用volumes[]部分定義的的卷名 20 mountPath: string #存儲卷在容器內mount的絕對路徑,應少於512字符 21 readOnly: boolean #是否為只讀模式,默認為讀寫模式 22 ports: #需要暴露的端口庫號列表 23 - name: string #端口的名稱 24 containerPort: int #容器需要監聽的端口號 25 hostPort: int #容器所在主機需要監聽的端口號,默認與Container相同 26 protocol: string #端口協議,支持TCP和UDP,默認TCP 27 env: #容器運行前需設置的環境變量列表 28 - name: string #環境變量名稱 29 value: string #環境變量的值 30 resources: #資源限制和請求的設置 31 limits: #資源限制的設置 32 cpu: string #CPU的限制,單位為core數,將用於docker run --cpu-shares參數 33 memory: string #內存限制,單位可以為Mib/Gib,將用於docker run --memory參數 34 requests: #資源請求的設置 35 cpu: string #CPU請求,容器啟動的初始可用數量 36 memory: string #內存請求,容器啟動的初始可用數量 37 livenessProbe: #對Pod內各容器健康檢查的設置,當探測無響應幾次后將自動重啟該容器,檢查方法有exec、httpGet和tcpSocket,對一個容器只需設置其中一種方法即可 38 exec: #對Pod容器內檢查方式設置為exec方式 39 command: [string] #exec方式需要制定的命令或腳本 40 httpGet: #對Pod內個容器健康檢查方法設置為HttpGet,需要制定Path、port 41 path: string 42 port: number 43 host: string 44 scheme: string 45 HttpHeaders: 46 - name: string 47 value: string 48 tcpSocket: #對Pod內個容器健康檢查方式設置為tcpSocket方式 49 port: number 50 initialDelaySeconds: 0 #容器啟動完成后首次探測的時間,單位為秒 51 timeoutSeconds: 0 #對容器健康檢查探測等待響應的超時時間,單位秒,默認1秒 52 periodSeconds: 0 #對容器監控檢查的定期探測時間設置,單位秒,默認10秒一次 53 successThreshold: 0 54 failureThreshold: 0 55 securityContext: 56 privileged: false 57 restartPolicy: [Always | Never | OnFailure] #Pod的重啟策略,Always表示一旦不管以何種方式終止運行,kubelet都將重啟,OnFailure表示只有Pod以非0退出碼退出才重啟,Nerver表示不再重啟該Pod 58 nodeSelector: obeject #設置NodeSelector表示將該Pod調度到包含這個label的node上,以key:value的格式指定 59 imagePullSecrets: #Pull鏡像時使用的secret名稱,以key:secretkey格式指定 60 - name: string 61 hostNetwork: false #是否使用主機網絡模式,默認為false,如果設置為true,表示使用宿主機網絡 62 volumes: #在該pod上定義共享存儲卷列表 63 - name: string #共享存儲卷名稱 (volumes類型有很多種) 64 emptyDir: {} #類型為emtyDir的存儲卷,與Pod同生命周期的一個臨時目錄。為空值 65 hostPath: string #類型為hostPath的存儲卷,表示掛載Pod所在宿主機的目錄 66 path: string #Pod所在宿主機的目錄,將被用於同期中mount的目錄 67 secret: #類型為secret的存儲卷,掛載集群與定義的secre對象到容器內部 68 scretname: string 69 items: 70 - key: string 71 path: string 72 configMap: #類型為configMap的存儲卷,掛載預定義的configMap對象到容器內部 73 name: string 74 items: 75 - key: string 76 path: string
Pod可以由1個或多個容器組合而成,通常對於緊耦合的兩個應用,應該組合成一個整體對外提供服務,則應該將這兩個打包為一個pod。
屬於一個Pod的多個容器應用之間相互訪問只需要通過localhost即可通信,這一組容器被綁定在一個環境中。
1 [root@k8smaster01 study]# vi frontend-localredis-pod.yaml 2 apiVersion: v1 3 kind: Pod 4 metadata: 5 name: redis-php 6 label: 7 name: redis-php 8 spec: 9 containers: 10 - name: frontend 11 image: kubeguide/guestbook-php-frontend:localredis 12 ports: 13 - containersPort: 80 14 - name: redis-php 15 image: kubeguide/redis-master 16 ports: 17 - containersPort: 6379 18 19 [root@k8smaster01 study]# kubectl create -f frontend-localredis-pod.yaml 20
1 [root@k8smaster01 study]# kubectl get pods #READY為2/2,表示此Pod中運行了yaml定義的兩個容器 2 NAME READY STATUS RESTARTS AGE 3 redis-php 2/2 Running 0 7m45s 4 [root@k8smaster01 study]# kubectl describe pod redis-php #查看詳細信息 5
靜態pod是由kubelet進行管理的僅存在於特定Node的Pod上,他們不能通過API Server進行管理,無法與ReplicationController、Deployment或者DaemonSet進行關聯,並且kubelet無法對他們進行健康檢查。靜態Pod總是由kubelet進行創建,並且總是在kubelet所在的Node上運行。
創建靜態Pod有兩種方式:配置文件或者HTTP方式。
1 [root@k8snode01 ~]# mkdir -p /etc/kubelet.d 2 [root@k8snode01 ~]# vi /etc/kubelet.d/static-web.yaml 3 apiVersion: v1 4 kind: Pod 5 metadata: 6 name: static-web 7 label: 8 name: static-web 9 spec: 10 containers: 11 - name: static-web 12 image: nginx 13 ports: 14 - name: web 15 containersPort: 80 16 17 [root@k8snode01 ~]# vi /etc/systemd/system/kubelet.service 18 …… 19 --config=/etc/kubelet.d/ \· #加入此參數 20 …… 21 [root@k8snode01 ~]# systemctl daemon-reload 22 [root@k8snode01 ~]# systemctl restart kubelet.service #重啟kubelet 23 [root@k8snode01 ~]# docker ps #查看創建的pod
提示:由於靜態pod不能通過API Server進行管理,因此在Master節點執行刪除操作後會變為Pending狀態,且無法刪除。刪除該pod只能在其運行的node上,將定義POD的yaml刪除。
通過設置kubelet的啟動參數–mainfest-url,會定期從該URL下載Pod的定義文件,並以.yaml或.json文件的格式進行解析,從而創建Pod。
在同一個Pod中的多個容器能夠共享Pod級別的存儲就Volume。Volume可以被定義為各種類型,多個容器各自進行掛載操作,將一個Volume掛載為容器內部需要的目錄。
示例1:
Pod級別設置Volume “app-logs”,同時Pod包含兩個容器,Tomcat向該Volume寫日誌,busybox讀取日誌文件。
1 [root@k8smaster01 study]# vi pod-volume-applogs.yaml 2 apiVersion: v1 3 kind: Pod 4 metadata: 5 name: volume-pod 6 spec: 7 containers: 8 - name: tomcat 9 image: tomcat 10 ports: 11 - containerPort: 8080 12 volumeMounts: 13 - name: app-logs 14 mountPath: /usr/local/tomcat/logs 15 - name: logreader 16 image: busybox 17 command: ["sh","-c","tail -f /logs/catalina*.log"] 18 volumeMounts: 19 - name: app-logs 20 mountPath: /logs 21 volumes: 22 - name: app-logs 23 emptyDir: {}
解釋:
Volume名:app-logs;
emptyDir:為Pod分配到Node的時候創建。無需指定宿主機的目錄文件,為Kubernetes自動分配的目錄。
1 [root@k8smaster01 study]# kubectl create -f pod-volume-applogs.yaml #創建 2 [root@k8smaster01 study]# kubectl get pods #查看 3 [root@k8smaster01 study]# kubectl logs volume-pod -c busybox #讀取log
1 [root@k8smaster01 study]# kubectl exec -it volume-pod -c tomcat -- ls /usr/local/tomcat/logs 2 catalina.2019-06-29.log localhost_access_log.2019-06-29.txt 3 host-manager.2019-06-29.log manager.2019-06-29.log 4 localhost.2019-06-29.log 5 [root@k8smaster01 study]# kubectl exec -it volume-pod -c tomcat -- tail /usr/local/tomcat/logs/catalina.2019-06-29.log
提示:通過tomcat容器可查看日誌,對比busybox通過共享Volume查看的日誌是否一致。
應用部署的一個最佳實踐是將應用所需的配置信息與程序進行分離,使程序更加靈活。將相應的應用打包為鏡像,可以通過環境變量或者外掛volume的方式在創建容器的時候進行配置注入,從而實現更好的復用。
Kubernetes提供一種統一的應用配置管理方案:ConfigMap。
ConfigMap供容器使用的主要場景:
ConfigMap以一個或多個key:value的形式定義。value可以是string也可以是一個文件內容,可以通過yaml配置文件或者通過kubectl create configmap 的方式創建configMap。
1 [root@k8smaster01 study]# vi cm-appvars.yaml 2 apiVersion: v1 3 kind: ConfigMap 4 metadata: 5 name: cm-appvars 6 data: 7 apploglevel: info 8 appdatadir: /var/data 9 10 [root@k8smaster01 study]# kubectl create -f cm-appvars.yaml 11 configmap/cm-appvars created 12 [root@k8smaster01 study]# kubectl get configmaps 13 NAME DATA AGE 14 cm-appvars 2 8s 15 [root@k8smaster01 study]# kubectl describe configmaps cm-appvars
1 [root@k8smaster01 study]# kubectl get configmaps cm-appvars -o yaml
語法1
1 # kubectl create configmap NAME --from-file=[key=]source --from-file=[key=]source
解釋:通過–from-file參數從文件中創建,可以指定key名稱,也可以制定多個key。
語法2
1 # kubectl create configmap NAME --from-file=config-files-dir
解釋:通過–from-file參數從目錄中創建,該目錄下的每個配置文件名都被設置為key,文件的內容被設置為value。
語法3
1 # kubectl create configmap NAME --from-literal=key1=value1 --from-literal=key2=value2
解釋:通過–from-literal參數從文本中創建,直接將指定的key#=value#創建為ConfigMap的內容。
容器應用使用ConfigMap有兩種方式:
1 [root@k8smaster01 study]# vi cm-test-pod.yaml 2 apiVersion: v1 3 kind: Pod 4 metadata: 5 name: cm-test-pod 6 spec: 7 containers: 8 - name: cm-test 9 image: busybox 10 command: ["/bin/sh","-c","env|grep APP"] #容器里執行查看環境變量的命令 11 env: 12 - name: APPLOGLEVEL #定義容器環境變量名稱 13 valueFrom: 14 configMapKeyRef: #環境變量的值來自ConfigMap 15 name: cm-appvars #指定來自cm-appvars的ConfigMap 16 key: apploglevel #key為apploglevel 17 - name: APPDATADIR 18 valueFrom: 19 configMapKeyRef: 20 name: cm-appvars 21 key: appdatadir 22 23 [root@k8smaster01 study]# kubectl create -f cm-test-pod.yaml 24 [root@k8smaster01 study]# kubectl get pods 25 NAME READY STATUS RESTARTS AGE 26 cm-test-pod 0/1 Completed 2 24s
【掛載形式-待補充】
pod擁有唯一的名字、IP地址,並且處於某個Namespace中。pod的容器內獲取pod的信息科通過Downward API實現。具體有以下兩種方式:
舉例1:通過Downward API將Pod的IP、名稱和所在的Namespace注入容器的環境變量。
1 [root@k8smaster01 study]# vi dapi-test-pod.yaml 2 apiVersion: v1 3 kind: Pod 4 metadata: 5 name: dapi-test-pod 6 spec: 7 containers: 8 - name: test-container 9 image: busybox 10 command: [ "/bin/sh", "-c", "env" ] 11 env: 12 - name: MY_POD_NAME 13 valueFrom: 14 fieldRef: 15 fieldPath: metadata.name 16 - name: MY_POD_NAMESPACE 17 valueFrom: 18 fieldRef: 19 fieldPath: metadata.namespace 20 - name: MY_POD_IP 21 valueFrom: 22 fieldRef: 23 fieldPath: status.podIP 24 restartPolicy: Never
提示:Downward API提供如下變量:
metadata.name:Pod的名稱,當Pod通過RC生成時,其名稱是RC隨機產生的唯一名稱;
status.podIP:Pod的IP地址,POd的IP屬於狀態數據,而非元數據;
metadata.namespace:Pod所在的namespace。
1 [root@k8smaster01 study]# kubectl create -f dapi-test-pod.yaml 2 [root@k8smaster01 study]# kubectl logs dapi-test-pod | grep MY_POD 3 MY_POD_NAMESPACE=default 4 MY_POD_IP=172.30.240.4 5 MY_POD_NAME=dapi-test-pod 6
舉例2:通過Downward API將Container的自願請求和限制信息注入容器的環境變量。
1 [root@k8smaster01 study]# vi dapi-test-pod-container-vars.yaml 2 apiVersion: v1 3 kind: Pod 4 metadata: 5 name: dapi-test-pod-container-vars 6 spec: 7 containers: 8 - name: test-container 9 image: busybox 10 imagePullPolicy: Never 11 command: [ "/bin/sh", "-c" ] 12 args: 13 - while true; do 14 echo -en '\n'; 15 printenv MY_CPU_REQUEST MY_CPU_LIMIT; 16 printenv MY_MEM_REQUEST MY_MEM_LIMIT; 17 sleep 3600; 18 done; 19 resources: 20 requests: 21 memory: "32Mi" 22 cpu: "125m" 23 limits: 24 memory: "64Mi" 25 cpu: "250m" 26 env: 27 - name: MY_CPU_REQUEST 28 valueFrom: 29 resourceFieldRef: 30 containerName: test-container 31 resource: requests.cpu 32 - name: MY_CPU_LIMIT 33 valueFrom: 34 resourceFieldRef: 35 containerName: test-container 36 resource: limits.cpu 37 - name: MY_MEM_REQUEST 38 valueFrom: 39 resourceFieldRef: 40 containerName: test-container 41 resource: requests.memory 42 - name: MY_MEM_LIMIT 43 valueFrom: 44 resourceFieldRef: 45 containerName: test-container 46 resource: limits.memory 47 restartPolicy: Never
提示:Downward API提供如下變量:
requests.cpu:容器的CPU請求值;
limits.cpu:容器的CPU限制值;
requests.memory:容器的內存請求值;
limits.memory:容器的內存限制值。
1 [root@k8smaster01 study]# kubectl create -f dapi-test-pod-container-vars.yaml 2 [root@k8smaster01 study]# kubectl logs dapi-test-pod-container-vars 3 1 4 1 5 33554432 6 67108864
舉例3:通過Downward API將Pod的Label、Annotation列表通過Volume掛載為容器內的一個文件。
1 [root@k8smaster01 study]# vi dapi-test-pod-volume.yaml 2 apiVersion: v1 3 kind: Pod 4 metadata: 5 name: dapi-test-pod-volume 6 labels: 7 zone: us-est-coast 8 cluster: test-cluster1 9 rack: rack-22 10 annotations: 11 build: two 12 builder: john-doe 13 spec: 14 containers: 15 - name: test-container 16 image: busybox 17 imagePullPolicy: Never 18 command: [ "/bin/sh", "-c" ] 19 args: 20 - while true; do 21 if [[ -e /etc/labels ]]; then 22 echo -en '\n\n'; cat /etc/labels; fi; 23 if [[ -e /etc/annotations ]]; then 24 echo -en '\n\n'; cat /etc/annotations; fi; 25 sleep 3600; 26 done; 27 volumeMounts: 28 - name: podinfo 29 mountPath: /etc 30 readOnly: false 31 volumes: 32 - name: podinfo 33 downwardAPI: 34 items: 35 - path: "labels" 36 fieldRef: 37 fieldPath: metadata.labels 38 - path: "annotations" 39 fieldRef: 40 fieldPath: metadata.annotations
注意:Volume中的ddownwardAPI的items語法,將會以path的名稱生成文件。如上所示,會在容器內生產/etc/labels和/etc/annotations兩個文件,分別包含metadata.labels和metadata.annotations的全部Label。
1 [root@k8smaster01 study]# kubectl create -f dapi-test-pod-volume.yaml 2 [root@k8smaster01 study]# kubectl logs dapi-test-pod-volume 3
提示:DownwardAPI意義:
在某些集群中,集群中的每個節點需要將自身的標識(ID)及進程綁定的IP地址等信息事先寫入配置文件中,進程啟動時讀取此類信息,然後發布到某個類似註冊服務中心。此時可通過DowanwardAPI,將一個預啟動腳本或Init Container,通過環境變量或文件方式獲取Pod自身的信息,然後寫入主程序配置文件中,最後啟動主程序。本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※帶您來了解什麼是 USB CONNECTOR ?
※自行創業 缺乏曝光? 下一步”網站設計“幫您第一時間規劃公司的門面形象
※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!
※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化
※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益
※試算大陸海運運費!
SpringBoot項目有一些基本的配置,比如啟動圖案(banner),比如默認配置文件application.properties,以及相關的默認配置項。
示例項目代碼在:
編寫banner.txt放入resources文件夾下,然後啟動項目即可修改默認圖案。
關於banner的生成,可以去一些專門的網站。
比如:https://www.bootschool.net/ascii
resources下通常會默認生成一個application.properties文件,這個文件包含了SpringBoot項目的全局配置文件。裏面的配置項通常是這樣的:
server.port=8080
在這個文件里我們可以添加框架支持的配置項,比如項目端口號、JDBC連接的數據源、日誌級別等等。
現在比較流行的是將properties文件改為yml文件。yml文件的格式yaml是這樣的:
server:
port: 8080
yml和properties的作用是一樣的。而yml的好處是顯而易見的——更易寫易讀。
屬性之間互相調用使用${name}:
eknown:
email: eknown@163.com
uri: http://www.eknown.cn
title: 'hello, link to ${eknown.uri} or email to ${eknown.email}'
鏈接:
通常開發一個應用會有多個環境,常見如dev/prod,也會有test,甚至其他一些自定義的環境,SpringBoot支持配置文件的靈活切換。
定義新配置文件需要遵循以下格式:application-{profile}.properties 或者application-{profile}.yml
比如現在有dev和prod兩個環境,我需要在application.yml文件之外新建兩個文件:
application-dev.yml
server: port: 8080application-prod.yml
server: port: 8081
然後在application.yml中通過application.profiles.active={profile}指明啟用那個配置:
application:
profiles:
active: dev
除了在application.yml中指定配置文件外,還可以通過啟動命令指定:java -jar xxx.jar --spring.profiles.active=dev
主要介紹兩種方式,獲取單個配置項和獲取多個配置項。
舉例:
eknown:
email: eknown@163.com
uri: http://www.eknown.cn
@Value("${eknown.email}")
private String email;
@Value("${eknown.uri}")
private String url;
注意:使用@Value註解的時候,所在類必須被Spring容器管理,也就是被@Component、@Controller、@Service等註解定義的類。
第一種,定義一個bean類,通過@Value獲取多個配置項:
@Component
public class MyConfigBean {
}
然後我們通過get方法來獲取這些值:
@RestController
public class BasicAction {
@Autowired
private MyConfigBean myConfigBean;
}
第二種,使用註解@ConfigurationProperties:
@Component
@ConfigurationProperties(perfix="eknown")
public class MyConfigBean {
private String email;
private String uri;
}
這裏只需要通過prefix指定前綴即可,後面的值自動匹配。
這裏我們還使用了@Component註解來讓spring容器管理這個MyConfigBean。
此外,我們可以不需要引入@Component,轉而在Application啟動類上加上@EnableConfigurationProperties({MyConfigBean.class})來啟動這個配置。
注意:我們這裡是從主配置文件,也就是SpringBoot默認的application-profile文件中獲取配置數據的。
而從自定義的配置文件,比如test.yml這種形式中獲取配置項時,情況是有點不大一樣的。
上面介紹的配置文件都是springboot默認的application開頭的文件。如果要自定義一個配置文件呢,比如test.yml或test.properties,怎麼獲取其中的配置項呢?
使用@PageResource註解即可。
首先我們來看一下讀取自定義的properties文件里的內容:
test.properties
hello.time=2019.11.19
hello.name=eknown
定義Configuration類:
@Configuration
@PropertySource("classpath:test.properties")
//@PropertySource("classpath:test.yml") // 注意,yml文件不能直接這樣寫,會讀不出數據
@ConfigurationProperties(prefix = "hello")
public class TestConfiguration {
private String name;
private String time;
// hide get and set methods
}
測試一下:
@RestController
@RequestMapping(value = "test")
public class TestAction {
@Autowired
private TestConfiguration testConfiguration;
@GetMapping(value = "config")
public String test() {
return testConfiguration.getName() + "<br/>" + testConfiguration.getTime();
}
}
如果將properties文件換成yml文件呢?
我們嘗試一下,發現:
讀不出數據?
分析一下@PropertySource註解,發現其使用的PropertySourceFactory是DefaultPropertySourceFactory.
這個類的源碼如下:
public class DefaultPropertySourceFactory implements PropertySourceFactory {
public DefaultPropertySourceFactory() {
}
public PropertySource<?> createPropertySource(@Nullable String name, EncodedResource resource) throws IOException {
return name != null ? new ResourcePropertySource(name, resource) : new ResourcePropertySource(resource);
}
}
這個類只能處理properties文件,無法處理yml文件。所以我們需要自定義一個YmlSourceFactory。
public class YamlSourceFactory extends DefaultPropertySourceFactory {
@Override
public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
return new YamlPropertySourceLoader().load(resource.getResource().getFilename()
, resource.getResource()).get(0);
}
}
然後定義test.yml文件的config類:
@Configuration
@PropertySource(value = "classpath:test.yml", encoding = "utf-8", factory = YamlSourceFactory.class)
@ConfigurationProperties(prefix = "yml.hello")
public class TestYamlConfiguration {
private String name;
private String time;
// hide get and set methods
}
注:為了區分test.properties和test.yml,這裏的test.yml中的屬性以yml.hello開頭。
編寫一下測試:
@Autowired
private TestYamlConfiguration ymlConfiguration;
@GetMapping(value = "yml")
public String testYml() {
return "yml config: <br/>" + ymlConfiguration.getName() + "<br/>" + ymlConfiguration.getTime();
}
訪問:
網上一些資料中,為配合使用@ConfigurationProperties,還使用了@EnableConfigurationProperties註解。
經過測試發現:
從SpringBoot默認配置文件讀取配置信息,使用@ConfigurationProperties + @Component/@Configuration,或者@ConfigurationProperties + 在啟動類添加@EnableConfigurationProperties({class})。這兩種方式都能解決問題
從非默認配置文件讀取配置信息,需要利用@PropertySource註解。同樣兩種方式:
2.1 @PropertySource + @ConfigurationProperties + @Component/@Configuration
2.2 @PropertySource + @ConfigurationProperties + @Component/@Configuration + @EnableConfigurationProperties,第二種方式存在一個問題,即還是必須要使用@Component註解,如果不使用,則會導致讀取配置信息為null,但程序不會報錯;而如果採用了,則會導致bean類的set方法被執行兩次(也就是生成了兩個同樣類型的bean類)。這種方式不建議!
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※為什麼 USB CONNECTOR 是電子產業重要的元件?
※網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!
※想要讓你的商品成為最夯、最多人討論的話題?網頁設計公司讓你強力曝光
※想知道最厲害的台北網頁設計公司推薦、台中網頁設計公司推薦專業設計師”嚨底家”!!
※專營大陸快遞台灣服務
※台灣快遞大陸的貨運公司有哪些呢?
今天我們緊接着上一篇繼續分享Appium自動化測試框架綜合實踐 – 代碼實現。到今天為止,大功即將告成;框架所需要的代碼實現都基本完成。
在實際項目過程中,我們的數據可能是存儲在一個數據文件中,如txt,excel、csv文件類型。我們可以封裝一些方法來讀取文件中的數據來實現數據驅動。
將測試賬號存儲在account.csv文件,內容如下:
|
hg2018 |
hg2018 |
|
hg2019 |
zxw2019 |
|
666 |
222 |
enumerate()是python的內置函數
如果對一個列表,既要遍歷索引又要遍曆元素時,首先可以這樣寫:
list = ["這", "是", "一個", "測試","數據"] for i in range(len(list)): print(i,list[i])
上述方法有些累贅,利用enumerate()會更加直接和優美:
list1 = ["這", "是", "一個", "測試","數據"] for index, item in enumerate(list1): print(index,item)
數據讀取方法也屬於公共方法,這裏我們首先實現一下,然後將其封裝到裡邊即可。
import csv def get_csv_data(csv_file,line): with open(csv_file, 'r', encoding='utf-8-sig') as file: reader=csv.reader(file) for index, row in enumerate(reader,1): if index == line: return row csv_file='../data/account.csv' data=get_csv_data(csv_file,3) print(data)
將其封裝在公共方法中,在其他地方用到的時候,直接導入調用即可。
UTF-8以字節為編碼單元,它的字節順序在所有系統中都是一樣的,沒有字節序的問題,也因此它實際上並不需要BOM(“ByteOrder Mark”)。但是UTF-8 with BOM即utf-8-sig需要提供BOM。
各種配置文件都放在這個目錄下。
主要是一些日誌信息的配置。
[loggers] keys=root,infoLogger [logger_root] level=DEBUG handlers=consoleHandler,fileHandler [logger_infoLogger] handlers=consoleHandler,fileHandler qualname=infoLogger propagate=0 [handlers] keys=consoleHandler,fileHandler [handler_consoleHandler] class=StreamHandler level=INFO formatter=form02 args=(sys.stdout,) [handler_fileHandler] class=FileHandler level=INFO formatter=form01 args=('../logs/runlog.log', 'a') [formatters] keys=form01,form02 [formatter_form01] format=%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s [formatter_form02] format=%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s
這裏宏哥舉例給小夥伴們演示:封裝註冊和登錄兩個測試用例。
測試用例執行開始和結束的封裝,其他模塊用到直接導入,調用即可。
# coding=utf-8 # 1.先設置編碼,utf-8可支持中英文,如上,一般放在第一行 # 2.註釋:包括記錄創建時間,創建人,項目名稱。 ''' Created on 2019-11-20 @author: 北京-宏哥 QQ交流群:707699217 Project:Appium自動化測試框架綜合實踐 - 代碼實現 ''' # 3.導入模塊 import unittest from kyb_testProject.common.desired_caps import appium_desired import logging from time import sleep class StartEnd(unittest.TestCase): def setUp(self): logging.info('=====setUp====') self.driver=appium_desired() def tearDown(self): logging.info('====tearDown====') sleep(5) self.driver.close_app()
開始註冊用例代碼邏輯的實現。
# coding=utf-8 # 1.先設置編碼,utf-8可支持中英文,如上,一般放在第一行 # 2.註釋:包括記錄創建時間,創建人,項目名稱。 ''' Created on 2019-11-20 @author: 北京-宏哥 QQ交流群:707699217 Project:Appium自動化測試框架綜合實踐 - 代碼實現 ''' # 3.導入模塊 from kyb_testProject.common.myunit import StartEnd from kyb_testProject.businessView.registerView import RegisterView import logging,random,unittest class RegisterTest(StartEnd): def test_user_register(self): logging.info('======test_user_register======') r=RegisterView(self.driver) username = 'bjhg2019' + 'fly' + str(random.randint(1000, 9000)) password = 'bjhg2020' + str(random.randint(1000, 9000)) email = 'bjhg' + str(random.randint(1000, 9000)) + '@163.com' self.assertTrue(r.register_action(username,password,email)) if __name__ == '__main__': unittest.main()
開始登錄用例代碼邏輯的實現。
# coding=utf-8 # 1.先設置編碼,utf-8可支持中英文,如上,一般放在第一行 # 2.註釋:包括記錄創建時間,創建人,項目名稱。 ''' Created on 2019-11-13 @author: 北京-宏哥 QQ交流群:707699217 Project:Appium自動化測試框架綜合實踐 - 代碼實現 ''' # 3.導入模塊 from kyb_testProject.common.myunit import StartEnd from kyb_testProject.businessView.loginView import LoginView import unittest import logging class TestLogin(StartEnd): csv_file='../data/account.csv' @unittest.skip('test_login_zxw2018') def test_login_zxw2018(self): logging.info('======test_login_zxw2018=====') l=LoginView(self.driver) data=l.get_csv_data(self.csv_file,2) l.login_action(data[0],data[1]) self.assertTrue(l.check_loginStatus()) # @unittest.skip('skip test_login_zxw2017') def test_login_zxw2017(self): logging.info('======test_login_zxw2017=====') l=LoginView(self.driver) data = l.get_csv_data(self.csv_file, 1) l.login_action(data[0], data[1]) self.assertTrue(l.check_loginStatus()) @unittest.skip('test_login_error') def test_login_error(self): logging.info('======test_login_error=====') l = LoginView(self.driver) data = l.get_csv_data(self.csv_file, 3) l.login_action(data[0], data[1]) self.assertTrue(l.check_loginStatus(),msg='login fail!') if __name__ == '__main__': unittest.main()
到此,Appium自動化測試框架就差下一篇就全部完成了,聰明的你都懂了嗎???嘿嘿!慢慢地來吧。
下一篇,講解執行測試用例,生成測試報告,以及自動化平台,請關注宏哥,敬請期待!!!
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能
※評比前十大台北網頁設計、台北網站設計公司知名案例作品心得分享
※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選
※台灣海運大陸貨務運送流程
※兩岸物流進出口一站式服務
Redis 提供了兩種持久化方式,一種是基於快照形式的 RDB,另一種是基於日誌形式的 AOF,每種方式都有自己的優缺點,本文將介紹 Redis 這兩種持久化方式,希望閱讀本文後你對 Redis 的這兩種方式有更加全面、清晰的認識。
先從 RDB 快照方式聊起,RDB 是 Redis 默認開啟的持久化方式,並不需要我們單獨開啟,先來看看跟 RDB 相關的配置信息:
################################ SNAPSHOTTING ################################
#
# Save the DB on disk:
#
# save <seconds> <changes>
#
# Will save the DB if both the given number of seconds and the given
# number of write operations against the DB occurred.
#
# In the example below the behaviour will be to save:
# after 900 sec (15 min) if at least 1 key changed
# after 300 sec (5 min) if at least 10 keys changed
# after 60 sec if at least 10000 keys changed
# save ""
# 自動生成快照的觸發機制 中間的是時間,單位秒,後面的是變更數據 60 秒變更 10000 條數據則自動生成快照
save 900 1
save 300 10
save 60 10000
# 生成快照失敗時,主線程是否停止寫入
stop-writes-on-bgsave-error yes
# 是否採用壓縮算法存儲
rdbcompression yes
# 數據恢復時是否檢測 RDB文件有效性
rdbchecksum yes
# The filename where to dump the DB
# RDB 快照生成的文件名稱
dbfilename dump.rdb
# 快照生成的路徑 AOF 也是存放在這個路徑下面
dir .
關於 RDB 相關配置信息不多,需要我們調整的就更少了,我們只需要根據自己的業務量修改生成快照的機制和文件存放路徑即可。
RDB 有兩種持久化方式:手動觸發 和 自動觸發,手動觸發使用以下兩個命令:
save:會阻塞當前 Redis 服務器響應其他命令,直到 RDB 快照生成完成為止,對於內存 比較大的實例會造成長時間阻塞,所以線上環境不建議使用
bgsave:Redis 主進程會 fork 一個子進程,RDB 快照生成有子進程來負責,完成之後,子進程自動結束,bgsave 只會在 fork 子進程的時候短暫的阻塞,這個過程是非常短的,所以推薦使用該命令來手動觸發
除了執行命令手動觸發之外,Redis 內部還存在自動觸發 RDB 的持久化機制,在以下幾種情況下 Redis 會自動觸發 RDB 持久化:
在配置中配置了 save 相關配置信息,如我們上面配置文件中的 save 60 10000 ,也可以把它歸類為“save m n”格式的配置,表示 m 秒內數據集存在 n 次修改時,會自動觸發 bgsave。
在主從情況下,如果從節點執行全量複製操作,主節點自動執行 bgsave 生成 RDB 文件併發送給從節點
執行 debug reload 命令重新加載 Redis 時,也會自動觸發 save 操作
默認情況下執行 shutdown 命令時,如果沒有開啟 AOF 持久化功能則自動執行 bgsave
上面就是 RDB 持久化的方式,可以看出 save 命令使用的比較少,大多數情況下使用的都是 bgsave 命令,所以這個 bgsave 命令還是有一些東西,那接下來我們就一起看看 bgsave 背後的原理,先從流程圖開始入手:
bgsave 命令大概有以下幾個步驟:
上面就是 bgsave 命令背後的一些內容,RDB 的內容就差不多了,我們一起來總結 RDB 持久化的優缺點,RDB 方式的優點:
有優點同樣存在缺點,RDB 的缺點有:
如果我們對數據要求比較高,每一秒的數據都不能丟,RDB 持久化方式肯定是不能夠滿足要求的,那 Redis 有沒有辦法滿足呢,答案是有的,那就是接下來的 AOF 持久化方式
Redis 默認並沒有開啟 AOF 持久化方式,需要我們自行開啟,在 redis.conf 配置文件中將 appendonly no 調整為 appendonly yes,這樣就開啟了 AOF 持久化,與 RDB 不同的是 AOF 是以記錄操作命令的形式來持久化數據的,我們可以查看以下 AOF 的持久化文件 appendonly.aof
*2
$6
SELECT
$1
0
*3
$3
set
$6
mykey1
$6
你好
*3
$3
set
$4
key2
$5
hello
*1
$8
大概就是長這樣的,具體的你可以查看你 Redis 服務器上的 appendonly.aof 配置文件,這也意味着我們可以在 appendonly.aof 文件中國修改值,等 Redis 重啟時將會加載修改之後的值。看似一些簡單的操作命令,其實從命令到 appendonly.aof 這個過程中非常有學問的,下面時 AOF 持久化流程圖:
在 AOF 持久化過程中有兩個非常重要的操作:一個是將操作命令追加到 AOF_BUF 緩存區,另一個是 AOF_buf 緩存區數據同步到 AOF 文件,接下來我們詳細聊一聊這兩個操作:
1、為什麼要將命令寫入到 aof_buf 緩存區而不是直接寫入到 aof 文件?
我們知道 Redis 是單線程響應,如果每次寫入 AOF 命令都直接追加到磁盤上的 AOF 文件中,這樣頻繁的 IO 開銷,Redis 的性能就完成取決於你的機器硬件了,為了提升 Redis 的響應效率就添加了一層 aof_buf 緩存層, 利用的是操作系統的 cache 技術,這樣就提升了 Redis 的性能,雖然這樣性能是解決了,但是同時也引入了一個問題,aof_buf 緩存區數據如何同步到 AOF 文件呢?由誰同步呢?這就是我們接下來要聊的一個操作:fsync 操作
2、aof_buf 緩存區數據如何同步到 aof 文件中?
aof_buf 緩存區數據寫入到 aof 文件是有 linux 系統去完成的,由於 Linux 系統調度機制周期比較長,如果系統故障宕機了,意味着一個周期內的數據將全部丟失,這不是我們想要的,所以 Linux 提供了一個 fsync 命令,fsync 是針對單個文件操作(比如這裏的 AOF 文件),做強制硬盤同步,fsync 將阻塞直到寫入硬盤完成后返回,保證了數據持久化,正是由於有這個命令,所以 redis 提供了配置項讓我們自行決定何時進行磁盤同步,redis 在 redis.conf 中提供了appendfsync 配置項,有如下三個選項:
# appendfsync always
appendfsync everysec
# appendfsync no
這就是三種磁盤同步策略,但是你有沒有注意到一個問題,AOF 文件都是追加的,隨着服務器的運行 AOF 文件會越來越大,體積過大的 AOF 文件對 redis 服務器甚至是主機都會有影響,而且在 Redis 重啟時加載過大的 AOF 文件需要過多的時間,這些都是不友好的,那 Redis 是如何解決這個問題的呢?Redis 引入了重寫機制來解決 AOF 文件過大的問題。
3、Redis 是如何進行 AOF 文件重寫的?
Redis AOF 文件重寫是把 Redis 進程內的數據轉化為寫命令同步到新 AOF 文件的過程,重寫之後的 AOF 文件會比舊的 AOF 文件占更小的體積,這是由以下幾個原因導致的:
重寫之後的 AOF 文件體積更小了,不但能夠節約磁盤空間,更重要的是在 Redis 數據恢復時,更小體積的 AOF 文件加載時間更短。AOF 文件重寫跟 RDB 持久化一樣分為手動觸發和自動觸發,手動觸發直接調用 bgrewriteaof 命令就好了,我們後面會詳細聊一聊這個命令,自動觸發就需要我們在 redis.conf 中修改以下幾個配置
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
滿足了這兩個條件,Redis 就會自動觸發 AOF 文件重寫,AOF 文件重寫的細節跟 RDB 持久化生成快照有點類似,下面是 AOF 文件重寫流程圖:
AOF 文件重寫也是交給子進程來完成,跟 RDB 生成快照很像,AOF 文件重寫在重寫期間建立了一個 aof_rewrite_buf 緩存區來保存重寫期間主進程響應的命令,等新的 AOF 文件重寫完成后,將這部分文件同步到新的 AOF 文件中,最後用新的 AOF 文件替換掉舊的 AOF 文件。需要注意的是在重寫期間,舊的 AOF 文件依然會進行磁盤同步,這樣做的目的是防止重寫失敗導致數據丟失,
我們知道 Redis 是基於內存的,所有的數據都存放在內存中,由於機器宕機或者其他因素重啟了就會導致我們的數據全部丟失,這也就是要做持久化的原因,當服務器重啟時,Redis 會從持久化文件中加載數據,這樣我們的數據就恢復到了重啟前的數據,在數據恢復這一塊Redis 是如何實現的?我們先來看看數據恢復的流程圖:
Redis 的數據恢複流程比較簡單,優先恢復的是 AOF 文件,如果 AOF 文件不存在時則嘗試加載 RDB 文件,為什麼 RDB 的恢復速度比 AOF 文件快,但是還是會優先加載 AOF 文件呢?我個人認為是 AOF 文件數據更全面並且 AOF 兼容性比 RDB 強,需要注意的是當存在 RDB/AOF 時,如果數據加載不成功,Redis 服務啟動會失敗。
目前互聯網上很多大佬都有 Redis 系列教程,如有雷同,請多多包涵了。原創不易,碼字不易,還希望大家多多支持。若文中有所錯誤之處,還望提出,謝謝。
歡迎掃碼關注微信公眾號:「平頭哥的技術博文」,和平頭哥一起學習,一起進步。
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包”嚨底家”
※網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線
※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整
※小三通海運與一般國際貿易有何不同?
※小三通快遞通關作業有哪些?