009.Kubernetes二進制部署kube-apiserver

一 部署master節點

1.1 master節點服務


kubernetes master 節點運行如下組件:

  • kube-apiserver
  • kube-scheduler
  • kube-controller-manager
  • kube-nginx


kube-apiserver、kube-scheduler 和 kube-controller-manager 均以多實例模式運行:

kube-scheduler 和 kube-controller-manager 會自動選舉產生一個 leader 實例,其它實例處於阻塞模式,當 leader 掛了后,重新選舉產生新的 leader,從而保證服務可用性。

kube-apiserver 是無狀態的,需要通過 kube-nginx 進行代理訪問,從而保證服務可用性。

1.2 安裝Kubernetes

  1 [root@k8smaster01 ~]# cd /opt/k8s/work
  2 [root@k8smaster01 work]# wget https://dl.k8s.io/v1.14.2/kubernetes-server-linux-amd64.tar.gz
  3 [root@k8smaster01 work]# tar -xzvf kubernetes-server-linux-amd64.tar.gz
  4 [root@k8smaster01 work]# cd kubernetes
  5 [root@k8smaster01 kubernetes]# tar -xzvf  kubernetes-src.tar.gz


1.3 分發Kubernetes

  1 [root@k8smaster01 ~]# cd /opt/k8s/work
  2 [root@k8smaster01 work]# source /opt/k8s/bin/environment.sh
  3 [root@k8smaster01 work]# for master_ip in ${MASTER_IPS[@]}
  4   do
  5     echo ">>> ${master_ip}"
  6     scp kubernetes/server/bin/{apiextensions-apiserver,cloud-controller-manager,kube-apiserver,kube-controller-manager,kube-proxy,kube-scheduler,kubeadm,kubectl,kubelet,mounter} root@${master_ip}:/opt/k8s/bin/
  7     ssh root@${master_ip} "chmod +x /opt/k8s/bin/*"
  8   done


二 部署高可用kube-apiserver

2.1 高可用apiserver介紹


本實驗部署一個三實例 kube-apiserver 集群的步驟,它們通過 kube-nginx 進行代理訪問,從而保證服務可用性。

2.2 創建Kubernetes證書和私鑰

  1 [root@k8smaster01 ~]# cd /opt/k8s/work
  2 [root@k8smaster01 work]# cat > kubernetes-csr.json <<EOF
  3 {
  4   "CN": "kubernetes",
  5   "hosts": [
  6     "127.0.0.1",
  7     "172.24.8.71",
  8     "172.24.8.72",
  9     "172.24.8.73",
 10     "${CLUSTER_KUBERNETES_SVC_IP}",
 11     "kubernetes",
 12     "kubernetes.default",
 13     "kubernetes.default.svc",
 14     "kubernetes.default.svc.cluster",
 15     "kubernetes.default.svc.cluster.local."
 16   ],
 17   "key": {
 18     "algo": "rsa",
 19     "size": 2048
 20   },
 21   "names": [
 22     {
 23       "C": "CN",
 24       "ST": "Shanghai",
 25       "L": "Shanghai",
 26       "O": "k8s",
 27       "OU": "System"
 28     }
 29   ]
 30 }
 31 EOF
 32 #創建Kubernetes的CA證書請求文件



解釋:

hosts 字段指定授權使用該證書的 IP 和域名列表,這裏列出了 master 節點 IP、kubernetes 服務的 IP 和域名;

kubernetes 服務 IP 是 apiserver 自動創建的,一般是 –service-cluster-ip-range 參數指定的網段的第一個IP,後續可以通過下面命令獲取:

  1 # kubectl get svc kubernetes




  1 [root@k8smaster01 ~]# cd /opt/k8s/work
  2 [root@k8smaster01 work]# cfssl gencert -ca=/opt/k8s/work/ca.pem \
  3 -ca-key=/opt/k8s/work/ca-key.pem -config=/opt/k8s/work/ca-config.json \
  4 -profile=kubernetes kubernetes-csr.json | cfssljson -bare kubernetes	#生成CA密鑰(ca-key.pem)和證書(ca.pem)


2.3 分發證書和私鑰

  1 [root@k8smaster01 ~]# cd /opt/k8s/work
  2 [root@k8smaster01 work]# source /opt/k8s/bin/environment.sh
  3 [root@k8smaster01 work]# for master_ip in ${MASTER_IPS[@]}
  4   do
  5     echo ">>> ${master_ip}"
  6     ssh root@${master_ip} "mkdir -p /etc/kubernetes/cert"
  7     scp kubernetes*.pem root@${master_ip}:/etc/kubernetes/cert/
  8   done


2.4 創建加密配置文件

  1 [root@k8smaster01 ~]# cd /opt/k8s/work
  2 [root@k8smaster01 work]# source /opt/k8s/bin/environment.sh
  3 [root@k8smaster01 work]# cat > encryption-config.yaml <<EOF
  4 kind: EncryptionConfig
  5 apiVersion: v1
  6 resources:
  7   - resources:
  8       - secrets
  9     providers:
 10       - aescbc:
 11           keys:
 12             - name: key1
 13               secret: ${ENCRYPTION_KEY}
 14       - identity: {}
 15 EOF


2.5 分發加密配置文件

  1 [root@k8smaster01 ~]# cd /opt/k8s/work
  2 [root@k8smaster01 work]# source /opt/k8s/bin/environment.sh
  3 [root@k8smaster01 work]# for master_ip in ${MASTER_IPS[@]}
  4   do
  5     echo ">>> ${master_ip}"
  6     scp encryption-config.yaml root@${master_ip}:/etc/kubernetes/
  7   done


2.6 創建審計策略文件

  1 [root@k8smaster01 ~]# cd /opt/k8s/work
  2 [root@k8smaster01 work]# source /opt/k8s/bin/environment.sh
  3 [root@k8smaster01 work]# cat > audit-policy.yaml <<EOF
  4 apiVersion: audit.k8s.io/v1beta1
  5 kind: Policy
  6 rules:
  7   # The following requests were manually identified as high-volume and low-risk, so drop them.
  8   - level: None
  9     resources:
 10       - group: ""
 11         resources:
 12           - endpoints
 13           - services
 14           - services/status
 15     users:
 16       - 'system:kube-proxy'
 17     verbs:
 18       - watch
 19 
 20   - level: None
 21     resources:
 22       - group: ""
 23         resources:
 24           - nodes
 25           - nodes/status
 26     userGroups:
 27       - 'system:nodes'
 28     verbs:
 29       - get
 30 
 31   - level: None
 32     namespaces:
 33       - kube-system
 34     resources:
 35       - group: ""
 36         resources:
 37           - endpoints
 38     users:
 39       - 'system:kube-controller-manager'
 40       - 'system:kube-scheduler'
 41       - 'system:serviceaccount:kube-system:endpoint-controller'
 42     verbs:
 43       - get
 44       - update
 45 
 46   - level: None
 47     resources:
 48       - group: ""
 49         resources:
 50           - namespaces
 51           - namespaces/status
 52           - namespaces/finalize
 53     users:
 54       - 'system:apiserver'
 55     verbs:
 56       - get
 57 
 58   # Don't log HPA fetching metrics.
 59   - level: None
 60     resources:
 61       - group: metrics.k8s.io
 62     users:
 63       - 'system:kube-controller-manager'
 64     verbs:
 65       - get
 66       - list
 67 
 68   # Don't log these read-only URLs.
 69   - level: None
 70     nonResourceURLs:
 71       - '/healthz*'
 72       - /version
 73       - '/swagger*'
 74 
 75   # Don't log events requests.
 76   - level: None
 77     resources:
 78       - group: ""
 79         resources:
 80           - events
 81 
 82   # node and pod status calls from nodes are high-volume and can be large, don't log responses for expected updates from nodes
 83   - level: Request
 84     omitStages:
 85       - RequestReceived
 86     resources:
 87       - group: ""
 88         resources:
 89           - nodes/status
 90           - pods/status
 91     users:
 92       - kubelet
 93       - 'system:node-problem-detector'
 94       - 'system:serviceaccount:kube-system:node-problem-detector'
 95     verbs:
 96       - update
 97       - patch
 98 
 99   - level: Request
100     omitStages:
101       - RequestReceived
102     resources:
103       - group: ""
104         resources:
105           - nodes/status
106           - pods/status
107     userGroups:
108       - 'system:nodes'
109     verbs:
110       - update
111       - patch
112 
113   # deletecollection calls can be large, don't log responses for expected namespace deletions
114   - level: Request
115     omitStages:
116       - RequestReceived
117     users:
118       - 'system:serviceaccount:kube-system:namespace-controller'
119     verbs:
120       - deletecollection
121 
122   # Secrets, ConfigMaps, and TokenReviews can contain sensitive & binary data,
123   # so only log at the Metadata level.
124   - level: Metadata
125     omitStages:
126       - RequestReceived
127     resources:
128       - group: ""
129         resources:
130           - secrets
131           - configmaps
132       - group: authentication.k8s.io
133         resources:
134           - tokenreviews
135   # Get repsonses can be large; skip them.
136   - level: Request
137     omitStages:
138       - RequestReceived
139     resources:
140       - group: ""
141       - group: admissionregistration.k8s.io
142       - group: apiextensions.k8s.io
143       - group: apiregistration.k8s.io
144       - group: apps
145       - group: authentication.k8s.io
146       - group: authorization.k8s.io
147       - group: autoscaling
148       - group: batch
149       - group: certificates.k8s.io
150       - group: extensions
151       - group: metrics.k8s.io
152       - group: networking.k8s.io
153       - group: policy
154       - group: rbac.authorization.k8s.io
155       - group: scheduling.k8s.io
156       - group: settings.k8s.io
157       - group: storage.k8s.io
158     verbs:
159       - get
160       - list
161       - watch
162 
163   # Default level for known APIs
164   - level: RequestResponse
165     omitStages:
166       - RequestReceived
167     resources:
168       - group: ""
169       - group: admissionregistration.k8s.io
170       - group: apiextensions.k8s.io
171       - group: apiregistration.k8s.io
172       - group: apps
173       - group: authentication.k8s.io
174       - group: authorization.k8s.io
175       - group: autoscaling
176       - group: batch
177       - group: certificates.k8s.io
178       - group: extensions
179       - group: metrics.k8s.io
180       - group: networking.k8s.io
181       - group: policy
182       - group: rbac.authorization.k8s.io
183       - group: scheduling.k8s.io
184       - group: settings.k8s.io
185       - group: storage.k8s.io
186 
187   # Default level for all other requests.
188   - level: Metadata
189     omitStages:
190       - RequestReceived
191 EOF


2.7 分發策略文件

  1 [root@k8smaster01 ~]# cd /opt/k8s/work
  2 [root@k8smaster01 work]# source /opt/k8s/bin/environment.sh
  3 [root@k8smaster01 work]# for master_ip in ${MASTER_IPS[@]}
  4   do
  5     echo ">>> ${master_ip}"
  6     scp audit-policy.yaml root@${master_ip}:/etc/kubernetes/audit-policy.yaml
  7   done


2.8 創建訪問 metrics-server的證書和密鑰

  1 [root@k8smaster01 ~]# cd /opt/k8s/work
  2 [root@k8smaster01 work]# cat > proxy-client-csr.json <<EOF
  3 {
  4   "CN": "aggregator",
  5   "hosts": [],
  6   "key": {
  7     "algo": "rsa",
  8     "size": 2048
  9   },
 10   "names": [
 11     {
 12       "C": "CN",
 13       "ST": "Shanghai",
 14       "L": "Shanghai",
 15       "O": "k8s",
 16       "OU": "System"
 17     }
 18   ]
 19 }
 20 EOF
 21 #創建metrics-server的CA證書請求文件



解釋:

CN 名稱需要位於 kube-apiserver 的 –requestheader-allowed-names 參數中,否則後續訪問 metrics 時會提示權限不足。

  1 [root@k8smaster01 ~]# cd /opt/k8s/work
  2 [root@k8smaster01 work]# cfssl gencert -ca=/opt/k8s/work/ca.pem \
  3 -ca-key=/opt/k8s/work/ca-key.pem -config=/opt/k8s/work/ca-config.json \
  4 -profile=kubernetes proxy-client-csr.json | cfssljson -bare proxy-client	#生成CA密鑰(ca-key.pem)和證書(ca.pem)


2.9 分發證書和私鑰

  1 [root@k8smaster01 ~]# cd /opt/k8s/work
  2 [root@k8smaster01 work]# source /opt/k8s/bin/environment.sh
  3 [root@k8smaster01 work]# for master_ip in ${MASTER_IPS[@]}
  4   do
  5     echo ">>> ${master_ip}"
  6     scp proxy-client*.pem root@${master_ip}:/etc/kubernetes/cert/
  7   done


2.10 創建kube-apiserver的systemd

  1 [root@k8smaster01 ~]# cd /opt/k8s/work
  2 [root@k8smaster01 work]# source /opt/k8s/bin/environment.sh
  3 [root@k8smaster01 work]# cat > kube-apiserver.service.template <<EOF
  4 [Unit]
  5 Description=Kubernetes API Server
  6 Documentation=https://github.com/GoogleCloudPlatform/kubernetes
  7 After=network.target
  8 
  9 [Service]
 10 WorkingDirectory=${K8S_DIR}/kube-apiserver
 11 ExecStart=/opt/k8s/bin/kube-apiserver \\
 12   --advertise-address=##MASTER_IP## \\
 13   --default-not-ready-toleration-seconds=360 \\
 14   --default-unreachable-toleration-seconds=360 \\
 15   --feature-gates=DynamicAuditing=true \\
 16   --max-mutating-requests-inflight=2000 \\
 17   --max-requests-inflight=4000 \\
 18   --default-watch-cache-size=200 \\
 19   --delete-collection-workers=2 \\
 20   --encryption-provider-config=/etc/kubernetes/encryption-config.yaml \\
 21   --etcd-cafile=/etc/kubernetes/cert/ca.pem \\
 22   --etcd-certfile=/etc/kubernetes/cert/kubernetes.pem \\
 23   --etcd-keyfile=/etc/kubernetes/cert/kubernetes-key.pem \\
 24   --etcd-servers=${ETCD_ENDPOINTS} \\
 25   --bind-address=##MASTER_IP## \\
 26   --secure-port=6443 \\
 27   --tls-cert-file=/etc/kubernetes/cert/kubernetes.pem \\
 28   --tls-private-key-file=/etc/kubernetes/cert/kubernetes-key.pem \\
 29   --insecure-port=0 \\
 30   --audit-dynamic-configuration \\
 31   --audit-log-maxage=15 \\
 32   --audit-log-maxbackup=3 \\
 33   --audit-log-maxsize=100 \\
 34   --audit-log-mode=batch \\
 35   --audit-log-truncate-enabled \\
 36   --audit-log-batch-buffer-size=20000 \\
 37   --audit-log-batch-max-size=2 \\
 38   --audit-log-path=${K8S_DIR}/kube-apiserver/audit.log \\
 39   --audit-policy-file=/etc/kubernetes/audit-policy.yaml \\
 40   --profiling \\
 41   --anonymous-auth=false \\
 42   --client-ca-file=/etc/kubernetes/cert/ca.pem \\
 43   --enable-bootstrap-token-auth \\
 44   --requestheader-allowed-names="aggregator" \\
 45   --requestheader-client-ca-file=/etc/kubernetes/cert/ca.pem \\
 46   --requestheader-extra-headers-prefix="X-Remote-Extra-" \\
 47   --requestheader-group-headers=X-Remote-Group \\
 48   --requestheader-username-headers=X-Remote-User \\
 49   --service-account-key-file=/etc/kubernetes/cert/ca.pem \\
 50   --authorization-mode=Node,RBAC \\
 51   --runtime-config=api/all=true \\
 52   --enable-admission-plugins=NodeRestriction \\
 53   --allow-privileged=true \\
 54   --apiserver-count=3 \\
 55   --event-ttl=168h \\
 56   --kubelet-certificate-authority=/etc/kubernetes/cert/ca.pem \\
 57   --kubelet-client-certificate=/etc/kubernetes/cert/kubernetes.pem \\
 58   --kubelet-client-key=/etc/kubernetes/cert/kubernetes-key.pem \\
 59   --kubelet-https=true \\
 60   --kubelet-timeout=10s \\
 61   --proxy-client-cert-file=/etc/kubernetes/cert/proxy-client.pem \\
 62   --proxy-client-key-file=/etc/kubernetes/cert/proxy-client-key.pem \\
 63   --service-cluster-ip-range=${SERVICE_CIDR} \\
 64   --service-node-port-range=${NODE_PORT_RANGE} \\
 65   --logtostderr=true \\
 66   --v=2
 67 Restart=on-failure
 68 RestartSec=10
 69 Type=notify
 70 LimitNOFILE=65536
 71 
 72 [Install]
 73 WantedBy=multi-user.target
 74 EOF



解釋:

  • –advertise-address:apiserver 對外通告的 IP(kubernetes 服務後端節點 IP);
  • –default-*-toleration-seconds:設置節點異常相關的閾值;
  • –max-*-requests-inflight:請求相關的最大閾值;
  • –etcd-*:訪問 etcd 的證書和 etcd 服務器地址;
  • –experimental-encryption-provider-config:指定用於加密 etcd 中 secret 的配置;
  • –bind-address: https 監聽的 IP,不能為 127.0.0.1,否則外界不能訪問它的安全端口 6443;
  • –secret-port:https 監聽端口;
  • –insecure-port=0:關閉監聽 http 非安全端口(8080);
  • –tls-*-file:指定 apiserver 使用的證書、私鑰和 CA 文件;
  • –audit-*:配置審計策略和審計日誌文件相關的參數;
  • –client-ca-file:驗證 client (kue-controller-manager、kube-scheduler、kubelet、kube-proxy 等)請求所帶的證書;
  • –enable-bootstrap-token-auth:啟用 kubelet bootstrap 的 token 認證;
  • –requestheader-*:kube-apiserver 的 aggregator layer 相關的配置參數,proxy-client & HPA 需要使用;
  • –requestheader-client-ca-file:用於簽名 –proxy-client-cert-file 和 –proxy-client-key-file 指定的證書;在啟用了 metric aggregator 時使用;
  • –requestheader-allowed-names:不能為空,值為逗號分割的 –proxy-client-cert-file 證書的 CN 名稱,這裏設置為 “aggregator”;
  • –service-account-key-file:簽名 ServiceAccount Token 的公鑰文件,kube-controller-manager 的 –service-account-private-key-file 指定私鑰文件,兩者配對使用;
  • –runtime-config=api/all=true: 啟用所有版本的 APIs,如 autoscaling/v2alpha1;
  • –authorization-mode=Node,RBAC、–anonymous-auth=false: 開啟 Node 和 RBAC 授權模式,拒絕未授權的請求;
  • –enable-admission-plugins:啟用一些默認關閉的 plugins;
  • –allow-privileged:運行執行 privileged 權限的容器;
  • –apiserver-count=3:指定 apiserver 實例的數量;
  • –event-ttl:指定 events 的保存時間;
  • –kubelet-*:如果指定,則使用 https 訪問 kubelet APIs;需要為證書對應的用戶(上面 kubernetes*.pem 證書的用戶為 kubernetes) 用戶定義 RBAC 規則,否則訪問 kubelet API 時提示未授權;
  • –proxy-client-*:apiserver 訪問 metrics-server 使用的證書;
  • –service-cluster-ip-range: 指定 Service Cluster IP 地址段;
  • –service-node-port-range: 指定 NodePort 的端口範圍。


提示:如果 kube-apiserver 機器沒有運行 kube-proxy,則還需要添加 –enable-aggregator-routing=true 參數。

注意:requestheader-client-ca-file 指定的 CA 證書,必須具有 client auth and server auth;

如果 –requestheader-allowed-names 為空,或者 –proxy-client-cert-file 證書的 CN 名稱不在 allowed-names 中,則後續查看 node 或 pods 的 metrics 失敗,提示:

  1 [root@zhangjun-k8s01 1.8+]# kubectl top nodes
  2 Error from server (Forbidden): nodes.metrics.k8s.io is forbidden: User "aggregator" cannot list resource "nodes" in API group "metrics.k8s.io" at the cluster scope
  3 


2.11 分發systemd

  1 [root@k8smaster01 ~]# cd /opt/k8s/work
  2 [root@k8smaster01 work]# source /opt/k8s/bin/environment.sh
  3 [root@k8smaster01 work]# for (( i=0; i < 3; i++ ))
  4   do
  5     sed -e "s/##MASTER_NAME##/${MASTER_NAMES[i]}/" -e "s/##MASTER_IP##/${MASTER_IPS[i]}/" kube-apiserver.service.template > kube-apiserver-${MASTER_IPS[i]}.service
  6   done
  7 [root@k8smaster01 work]# ls kube-apiserver*.service			#替換相應的IP
  8 [root@k8smaster01 ~]# cd /opt/k8s/work
  9 [root@k8smaster01 work]# source /opt/k8s/bin/environment.sh
 10 [root@k8smaster01 work]# for master_ip in ${MASTER_IPS[@]}
 11   do
 12     echo ">>> ${master_ip}"
 13     scp kube-apiserver-${master_ip}.service root@${master_ip}:/etc/systemd/system/kube-apiserver.service
 14   done						                #分發systemd


三 啟動並驗證

3.1 啟動kube-apiserver服務

  1 [root@k8smaster01 ~]# source /opt/k8s/bin/environment.sh
  2 [root@k8smaster01 ~]# for master_ip in ${MASTER_IPS[@]}
  3   do
  4     echo ">>> ${master_ip}"
  5     ssh root@${master_ip} "mkdir -p ${K8S_DIR}/kube-apiserver"
  6     ssh root@${master_ip} "systemctl daemon-reload && systemctl enable kube-apiserver && systemctl restart kube-apiserver"
  7   done


3.2 檢查kube-apiserver服務

  1 [root@k8smaster01 ~]# source /opt/k8s/bin/environment.sh
  2 [root@k8smaster01 ~]# for master_ip in ${MASTER_IPS[@]}
  3   do
  4     echo ">>> ${master_ip}"
  5     ssh root@${master_ip} "systemctl status kube-apiserver |grep 'Active:'"
  6   done


3.3 查看kube-apiserver寫入etcd的數據

  1 [root@k8smaster01 ~]# source /opt/k8s/bin/environment.sh
  2 [root@k8smaster01 ~]# ETCDCTL_API=3 etcdctl \
  3     --endpoints=${ETCD_ENDPOINTS} \
  4     --cacert=/opt/k8s/work/ca.pem \
  5     --cert=/opt/k8s/work/etcd.pem \
  6     --key=/opt/k8s/work/etcd-key.pem \
  7     get /registry/ --prefix --keys-only


3.4 檢查集群信息

  1 [root@k8smaster01 ~]# kubectl cluster-info
  2 [root@k8smaster01 ~]# kubectl get all --all-namespaces
  3 [root@k8smaster01 ~]# kubectl get componentstatuses
  4 [root@k8smaster01 ~]# sudo netstat -lnpt|grep kube		#檢查 kube-apiserver 監聽的端口





提示:

如果執行 kubectl 命令式時輸出如下錯誤信息,則說明使用的 ~/.kube/config 文件不對,請切換到正確的賬戶后再執行該命令:

The connection to the server localhost:8080 was refused – did you specify the right host or port?

執行 kubectl get componentstatuses 命令時,apiserver 默認向 127.0.0.1 發送請求。當 controller-manager、scheduler 以集群模式運行時,有可能和 kube-apiserver 不在一台機器上,這時 controller-manager 或 scheduler 的狀態為 Unhealthy,但實際上它們工作正常;

6443: 接收 https 請求的安全端口,對所有請求做認證和授權;

由於關閉了非安全端口,故沒有監聽 8080。

3.5 授權


授予 kube-apiserver 訪問 kubelet API 的權限。

在執行 kubectl exec、run、logs 等命令時,apiserver 會將請求轉發到 kubelet 的 https 端口。本實驗定義 RBAC 規則,授權 apiserver 使用的證書(kubernetes.pem)用戶名(CN:kuberntes)訪問 kubelet API 的權限:

  1 [root@k8smaster01 ~]# kubectl create clusterrolebinding kube-apiserver:kubelet-apis --clusterrole=system:kubelet-api-admin --user kubernetes

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置台北網頁設計,各種案例分享

Unity中用Mesh畫一個圓環(二)

中目標-生成完整面

在之前的內容中我們已經成功生成了一個面,接下來我們要生成剩下的面就很容易了。

我們把之前生成的面當作頂面,接着我們來生成底面。

還記得前面說過\(\color{#1E90FF}{Depth}\)這個參數用來控制深度,也就是頂面和地面之間的距離,放到坐標系中就是控制Z的位置。

底面和頂面的頂點生成方法是一樣的,唯一不同的地方就是Z軸的不同。 我們只要用生成頂面的方法改下Z坐標,就可以得到底面了。

//下
        for (int i = 0; i <= NumberOfSides; i++)
        {
            float angle = 180 - i * incrementAngle;
            float innerX = (Radius - Thickness) * Mathf.Cos(angle * Mathf.Deg2Rad);
            float innerY = (Radius - Thickness) * Mathf.Sin(angle * Mathf.Deg2Rad);
            vertexList.Add(new Vector3(innerX, innerY, -1 * Depth / 2));
            float outsideX = Radius * Mathf.Cos(angle * Mathf.Deg2Rad);
            float outsideY = Radius * Mathf.Sin(angle * Mathf.Deg2Rad);
            vertexList.Add(new Vector3(outsideX, outsideY, - 1 * Depth / 2));
        }

三角形索引的生成和之前也是一樣的,不同的是一開始的方向,因為頂面的法線是向上的,而底面的法線是向下的:

  direction = 1;
        startIndex += (NumberOfSides + 1) * 2;
        for (int i = 0; i < NumberOfSides * 2; i++)
        {
            int[] triangleIndexs = getTriangleIndexs(i, direction, startIndex);
            direction *= -1;
            for (int j = 0; j < triangleIndexs.Length; j++)
            {
                triangleList.Add(triangleIndexs[j]);
            }
        }

至於UV索引則設置和頂面的一樣即可。

其實生成頂面和底面之後,大部分的工作已經完成了,這時候我們已經生成了我們需要的所有頂點。前後左右也只是用現有的這些頂點進行生成。

我們前面生成的圓柱體是基於圓生成的,如果我們改成基於貝塞爾生成的那也是可以的。

修改方法很簡單,就是改下生成頂點時的過程就好了,其他的不需要動。

具體過程直接看代碼吧,包看包懂。

當然下面的代碼是為了方面理解所以寫得冗餘,如果用到項目中建議優化下,不然會被主程打的。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//[RequireComponent(typeof(MeshFilter))]
//[RequireComponent(typeof(MeshRenderer))]
[ExecuteInEditMode]
public class DrawArch : MonoBehaviour
{
    public float Radius = 20.0f;                //外圈的半徑
    public float Thickness = 10.0f;             //厚度,外圈半徑減去內圈半徑
    public float Depth = 1.0f;                  //厚度
    public int NumberOfSides = 30;         //由多少個面組成
    public float DrawArchDegrees = 90.0f;       //要繪畫多長
    public Vector2[] bezierPoints = new Vector2[4];
    public Material archMaterial = null;

    private int VertexCountOneSide = 0;         //生成一面所需的頂點數
    private Mesh mesh = null;

    private float incrementAngle = 0;
    private List<Vector3> vertexList = new List<Vector3>();
    private List<int> triangleList = new List<int>();
    private List<Vector2> uvList = new List<Vector2>();

    // Start is called before the first frame update
    void Start()
    {
        mesh = new Mesh();
    }

    void GenerateMesh()
    {
        VertexCountOneSide = (NumberOfSides + 1) * 2;
        incrementAngle = DrawArchDegrees / NumberOfSides;

        GenerateVertex();
        GenerateTriangleIndex();
        GenerateUV();

        mesh.vertices = vertexList.ToArray();
        mesh.uv = uvList.ToArray();
        mesh.triangles = triangleList.ToArray();

        mesh.RecalculateNormals();
        gameObject.GetComponent<MeshFilter>().mesh = mesh;
        gameObject.GetComponent<MeshRenderer>().material = archMaterial;
    }

    //生成頂點坐標
    void GenerateVertex()
    {
        //上
        vertexList.Clear();
        for (int i = 0; i <= NumberOfSides; i++)
        {
            //float[] points = GetCirclePoint(Radius - Thickness,  i);
            //vertexList.Add(new Vector3(points[0], points[1], Depth / 2));
            //points = GetCirclePoint(Radius, i);
            //vertexList.Add(new Vector3(points[0], points[1], Depth / 2));
            float[] points = GetBezierPoint(i);
            vertexList.Add(new Vector3(points[0], points[1], Depth / 2));
            points = GetBezierPoint(i);
            vertexList.Add(new Vector3(points[0] - 1, points[1], Depth / 2));
        }

        //下
        for (int i = 0; i <= NumberOfSides; i++)
        {
            //float[] points = GetCirclePoint(Radius - Thickness,  i);
            //vertexList.Add(new Vector3(points[0], points[1], -1 * Depth / 2));
            //points = GetCirclePoint(Radius, i);
            //vertexList.Add(new Vector3(points[0], points[1], -1 * Depth / 2));
            float[] points = GetBezierPoint(i);
            vertexList.Add(new Vector3(points[0], points[1], -1 * Depth / 2));
            points = GetBezierPoint(i);
            vertexList.Add(new Vector3(points[0] - 1, points[1], -1 * Depth / 2));
        }

        //前
        for (int i = 0; i <= NumberOfSides * 2 ; i += 2)
        {
            vertexList.Add(vertexList[i]);
            vertexList.Add(vertexList[i + VertexCountOneSide]);
        }
        //后
        for (int i = 0; i <= NumberOfSides * 2; i += 2)
        {
            vertexList.Add(vertexList[i + 1]);
            vertexList.Add(vertexList[i + VertexCountOneSide + 1]);
        }
        //左
        vertexList.Add(vertexList[0]);
        vertexList.Add(vertexList[1]);
        vertexList.Add(vertexList[VertexCountOneSide + 0]);
        vertexList.Add(vertexList[VertexCountOneSide + 1]);
        //右
        vertexList.Add(vertexList[VertexCountOneSide -2]);
        vertexList.Add(vertexList[VertexCountOneSide - 1]);
        vertexList.Add(vertexList[VertexCountOneSide * 2 - 2]);
        vertexList.Add(vertexList[VertexCountOneSide * 2 - 1]);
    }

    void GenerateTriangleIndex()
    {
        //三角形索引
        triangleList.Clear();
        //上
        int direction = -1;
        int startIndex = 0;
        for (int i = 0; i < NumberOfSides * 2; i++)
        {
            int[] triangleIndexs = getTriangleIndexs(i, direction);
            direction *= -1;
            for (int j = 0; j < triangleIndexs.Length; j++)
            {
                triangleList.Add(triangleIndexs[j]);
            }
        }

        //下
        direction = 1;
        startIndex += (NumberOfSides + 1) * 2;
        for (int i = 0; i < NumberOfSides * 2; i++)
        {
            int[] triangleIndexs = getTriangleIndexs(i, direction, startIndex);
            direction *= -1;
            for (int j = 0; j < triangleIndexs.Length; j++)
            {
                triangleList.Add(triangleIndexs[j]);
            }
        }

        //前
        direction = 1;
        startIndex += VertexCountOneSide;
        for (int i = 0; i < NumberOfSides * 2; i++)
        {
            int[] triangleIndexs = getTriangleIndexs(i, direction, startIndex);
            direction *= -1;
            for (int j = 0; j < triangleIndexs.Length; j++)
            {
                triangleList.Add(triangleIndexs[j]);
            }
        }

        //后
        direction = -1;
        startIndex += VertexCountOneSide;
        for (int i = 0; i < NumberOfSides * 2; i++)
        {
            int[] triangleIndexs = getTriangleIndexs(i, direction, startIndex);
            direction *= -1;
            for (int j = 0; j < triangleIndexs.Length; j++)
            {
                triangleList.Add(triangleIndexs[j]);
            }
        }
        startIndex += VertexCountOneSide;
        //左
        triangleList.Add(startIndex + 0);
        triangleList.Add(startIndex + 1);
        triangleList.Add(startIndex + 2);
        triangleList.Add(startIndex + 3);
        triangleList.Add(startIndex + 2);
        triangleList.Add(startIndex + 1);
        //右
        triangleList.Add(startIndex + 4 + 2);
        triangleList.Add(startIndex + 4 + 1);
        triangleList.Add(startIndex + 4 + 0);
        triangleList.Add(startIndex + 4 + 1);
        triangleList.Add(startIndex + 4 + 2);
        triangleList.Add(startIndex + 4 + 3);
    }

    //UV索引
    void GenerateUV()
    {
        uvList.Clear();
        //上
        for (int i = 0; i <= NumberOfSides; i++)
        {
            float angle = 180 - i * incrementAngle;
            float littleX = (1.0f / NumberOfSides) * i;
            uvList.Add(new Vector2(littleX, 0));
            float bigX = (1.0f / NumberOfSides) * i;
            uvList.Add(new Vector2(bigX, 1));
        }

        //下
        for (int i = 0; i <= NumberOfSides; i++)
        {
            float angle = 180 - i * incrementAngle;
            float littleX = (1.0f / NumberOfSides) * i;
            uvList.Add(new Vector2(littleX, 0));
            float bigX = (1.0f / NumberOfSides) * i;
            uvList.Add(new Vector2(bigX, 1));
        }

        //前
        for (int i = 0; i <= NumberOfSides; i++)
        {
            float angle = 180 - i * incrementAngle;
            float littleX = (1.0f / NumberOfSides) * i;
            uvList.Add(new Vector2(littleX, 0));
            float bigX = (1.0f / NumberOfSides) * i;
            uvList.Add(new Vector2(bigX, 1));
        }

        //后
        for (int i = 0; i <= NumberOfSides; i++)
        {
            float angle = 180 - i * incrementAngle;
            float littleX = (1.0f / NumberOfSides) * i;
            uvList.Add(new Vector2(littleX, 0));
            float bigX = (1.0f / NumberOfSides) * i;
            uvList.Add(new Vector2(bigX, 1));
        }
        //左
        uvList.Add(new Vector2(1.0f, 1.0f));
        uvList.Add(new Vector2(0.0f, 1.0f));
        uvList.Add(new Vector2(0.0f, 0.0f));
        uvList.Add(new Vector2(1.0f, 0.0f));
        //右
        uvList.Add(new Vector2(1.0f, 1.0f));
        uvList.Add(new Vector2(0.0f, 1.0f));
        uvList.Add(new Vector2(0.0f, 0.0f));
        uvList.Add(new Vector2(1.0f, 0.0f));
    }

    int[] getTriangleIndexs(int index, int direction, int startIndex = 0)
    {
        int[] triangleIndexs = new int[3] { 0+ startIndex, 1 + startIndex, 2 + startIndex };
        for (int i = 0; i < triangleIndexs.Length; i++)
        {
            triangleIndexs[i] += index;
        }
        if (direction == -1)
        {
            int temp = triangleIndexs[0];
            triangleIndexs[0] = triangleIndexs[2];
            triangleIndexs[2] = temp;
        }
        return triangleIndexs;
    }

    private void Update()
    {
        GenerateMesh();
    }

    float[] GetCirclePoint(float radius, int index)
    {
        float angle = 180 - index * incrementAngle;
        float[] points = new float[2];
        float x = radius * Mathf.Cos(angle * Mathf.Deg2Rad);
        float y = radius * Mathf.Sin(angle * Mathf.Deg2Rad);
        points[0] = x;
        points[1] = y;
        return points;
    }

    float[] GetBezierPoint(int index)
    {
        float t = 1.0f / (NumberOfSides + 1) * index;
        float[] points = new float[2];
        var vec = Bezier(bezierPoints[0], bezierPoints[1], bezierPoints[2], bezierPoints[3], t);
        points[0] = vec.x;
        points[1] = vec.y;
        return points;
    }

    Vector2 Bezier(Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3, float t)
    {
        Vector2 result;
        Vector2 p0p1 = (1 - t) * p0 + t * p1;
        Vector2 p1p2 = (1 - t) * p1 + t * p2;
        Vector2 p2p3 = (1 - t) * p2 + t * p3;
        Vector2 p0p1p2 = (1 - t) * p0p1 + t * p1p2;
        Vector2 p1p2p3 = (1 - t) * p1p2 + t * p2p3;
        result = (1 - t) * p0p1p2 + t * p1p2p3;
        return result;
    }
}

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

南投搬家前需注意的眉眉角角,別等搬了再說!

C# web項目中sql數據庫轉sqlite數據庫

最近做了一個小網站,用到了一個使用sql server 2005的.net cms系統,但是現在我所買虛擬主機的服務商,不給虛擬主機提供sql server服務了,那就轉數據庫吧,轉啥好呢,思來想去,access?剛入行時候用了很久,簡單夠用,不過實在提不起興趣了,sqlite?嗯…還沒用過,只是簡單看過介紹,聽說性能還不錯,那就試試吧,等等,不知道虛擬主機支持不支持?!百度!然而一大堆沒啥用處的提問和回答,也許可能大概是我搜索的關鍵詞不對,懶得管了,年齡大了,沒有那個勁兒了,實踐出真理,先上手試試驗證一下吧,說干就干

先查查怎麼在本地創建和管理數據庫,然後選擇使用了SQLiteStudio這個軟件,然後新建個test數據庫->隨便插條數據->然後在vs創建個test web項目->數據庫文件扔進去->新建個頁面,查下數據显示到頁面->本地運行,ok!,發布,->上傳虛擬主機,懷着稍稍激動的心情,打開網址,ok!完全可以!

這麼簡單嗎?nonono,運行之前還是有點小小的障礙的:

首先項目需要用到System.Data.SQLite.dll,到sqlite官網下一個吧,

然後添加引用,引用之後,還需要連接字符串,搜索(ss)! 嗯,和access很像,附個例子:

<add name="ConnectionString" connectionString="Data Source=|DataDirectory|testdb.db;Version=3;Pooling=true;FailIfMissing=false" providerName="System.Data.SQLite" />

這樣就可以運行了!具體的參數還有不少,ss一下,根據需求自己設置。

然後開始改cms吧,首先是轉數據庫,一看錶,我尼瑪,好多表,自己一個一個建嗎?想想都想打消折騰的念頭了,有沒有什麼工具可以藉助呢?ss一下,還真有!

SQL server To SQLite DB Convert 這是一位叫liron.levi老外寫的,項目地址:https://www.codeproject.com/Articles/26932/Convert-SQL-Server-DB-to-SQLite-DB

簡直神器,界面如下

 作者還給出了源代碼,在源代碼中可以看到數據類型對應的轉換

        /// <summary>
        /// Used when creating the CREATE TABLE DDL. Creates a single row
        /// for the specified column.
        /// </summary>
        /// <param name="col">The column schema</param>
        /// <returns>A single column line to be inserted into the general CREATE TABLE DDL statement</returns>
        private static string BuildColumnStatement(ColumnSchema col, TableSchema ts, ref bool pkey)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("\t[" + col.ColumnName + "]\t");

            // Special treatment for IDENTITY columns
            if (col.IsIdentity)
            {
                if (ts.PrimaryKey.Count == 1 && (col.ColumnType == "tinyint" || col.ColumnType == "int" || col.ColumnType == "smallint" ||
                    col.ColumnType == "bigint" || col.ColumnType == "integer"))
                {
                    sb.Append("integer PRIMARY KEY AUTOINCREMENT");
                    pkey = true;
                }
                else
                    sb.Append("integer");
            }
            else
            {
                if (col.ColumnType == "int")
                    sb.Append("integer");
                else
                {
                    sb.Append(col.ColumnType);
                }
                if (col.Length > 0)
                    sb.Append("(" + col.Length + ")");
            }
            if (!col.IsNullable)
                sb.Append(" NOT NULL");

            if (col.IsCaseSensitivite.HasValue && !col.IsCaseSensitivite.Value)
                sb.Append(" COLLATE NOCASE");

            string defval = StripParens(col.DefaultValue);
            defval = DiscardNational(defval);
            _log.Debug("DEFAULT VALUE BEFORE [" + col.DefaultValue + "] AFTER [" + defval + "]");
            if (defval != string.Empty && defval.ToUpper().Contains("GETDATE"))
            {
                _log.Debug("converted SQL Server GETDATE() to CURRENT_TIMESTAMP for column [" + col.ColumnName + "]");
                sb.Append(" DEFAULT (CURRENT_TIMESTAMP)");
            }
            else if (defval != string.Empty && IsValidDefaultValue(defval))
                sb.Append(" DEFAULT " + defval);

            return sb.ToString();
        }

View Code

然後就用這個工具把cms的sql server數據庫轉換成sqlite數據庫文件,直接扔進cms項目中。

這樣就行了嗎?當然還有工作要做,原來項目中操作sql server的類庫也要換成sqlite的,sql語句也要做相應的轉換,下面就挑一些重點的說一說:

先說數據類型吧:

由於在工具的源代碼中,主鍵不管什麼類型的int轉成sqlite都用的integer,有需求的可以自己改代碼,不過最好要熟悉sqlite的數據類型。下面列出我在項目中所遇到的主要類型轉換

sql server c# sqlite c#
int new SqlParameter(“@id”, SqlDbType.Int,4)  integer new SQLiteParameter(“@id”, DbType.Int64,8)
nvarchar new SqlParameter(“@id”, SqlDbType.NVarChar,50) nvarchar new SQLiteParameter(“@id”, DbType.String,50)
decimal new SqlParameter(“@id”, SqlDbType.Decimal) numeric new SQLiteParameter(“@id”, DbType.Decimal)
tinyint new SqlParameter(“@id”, SqlDbType.TinyInt,1) smallint new SQLiteParameter(“@id”, DbType.Int16,1)
ntext new SqlParameter(“@id”, SqlDbType.NText) text new SQLiteParameter(“@id”, DbType.String)
datetime new SqlParameter(“@id”, SqlDbType.DateTime) datetime new SQLiteParameter(“@id”, DbType.DateTime)
Image new SqlParameter(“@fs”, SqlDbType.Image) Binary new SQLiteParameter(“@fs”, DbType.Binary)

 

代碼數據類型轉換之後,就剩調試修改sql語句了,下面列出我在項目中遇到的比較主要的轉換

1、top語句,在sqlite中要使用limit,和mysql差不多,例如

  sql:select top 10 * from table_1

  sqlite:select * from table_1 limit 10

2、在插入一條數據后,要獲取最新的id

  sql:select @@IDENTITY;

  sqlite:select LAST_INSERT_ROWID();

3、計算時間差

  sql:where datediff(d,field_time,getdate())>=0

  sqlite:where JULIANDAY(datetime('now','localtime'))-JULIANDAY(field_time)>=0

4、分頁

  sql:2005以上一般使用ROW_NUMBER()  

    select * from ( select row_number() over(order by id) as rows,* ) as t where rows between PageIndex*PageSize and PageIndex*PageSize+PageSize

  sqlite:用 limit  offset

    select * from table_1 limit PageSize offset (PageIndex- 1) * PageSize 

5、最讓人抓狂的是修改表部分的差異

  這一部分單獨再寫一篇吧

時間不早了,來自老年人的嘆息…..

第二天了,附上修改表的文章鏈接:

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

特斯拉盼於德國設廠 因環保問題遭抗議

摘錄自2020年01月19日中央通訊社德國報導

美國電動車大廠特斯拉(Tesla)計畫在柏林郊區設立超級工廠,大約250名德國民眾今天(19日)到設廠地點抗議,宣稱這樣的建設將會危害區域內的水源供應和野生生物。

特斯拉去年11月宣布,計畫在德國東部布蘭登堡邦(Brandenburg)市鎮格林海德(Grünheide)設立他們在歐洲的第一座工廠。政界、工會、產業團體都對特斯拉表示歡迎,宣稱那會為地區帶來工作機會,但因為對環境保護的憂慮,讓數百名當地人在今天走上街頭。

在此之前,布蘭登堡邦水利當局16日警告,預定興建的特斯拉工廠,將使得「飲水供應以及工廠廢水排放,出現廣泛及嚴重的問題。」

同時,民眾也為附近道路和村落之間的交通憂心不已,他們預期交通未來會有「巨幅」成長,他們為此表達抗議。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

不顧澳洲乾旱缺水 中資度假村抽水外銷惹眾怒

摘錄自2020年01月17日中央通訊社澳洲報導

澳洲昆士蘭州南原區(Southern Downs Region)旱災肆虐又遭野火侵襲,用水嚴重受限,一家中資度假村卻還獲准每年抽取近1億公升地下水外銷,引發當地民眾強烈不滿。

澳洲廣播公司新聞網(ABC News)和「澳洲人報」(The Australian )報導,中國的中山皇爵盈富公司擁有的4星卓爾巴度假村(Cherrabah Resort),位在昆士蘭州(Queensland)華瑞克(Warwick)附近的肘谷(Elbow Valley),飯店周圍牧地乾旱情況嚴重。

鄰近城市斯坦索普(Stanthorpe)供水已吃緊,居民仰賴水車從75公里遠的水壩運水過來。南原區區議會也準備限制區內民眾每人每日最多用水80公升,並習慣洗澡不超過3分鐘及每3天才洗衣服。

然而,區議會去年耶誕節前卻通過卓爾巴度假村提出的計畫,允許在度假村內設置抽水和淨水設施,每年可從含水層抽取最多9600萬公升的地下水,並送往澳洲沿海城市黃金海岸(Gold Coast)進行商業裝瓶販售。

根據中山皇爵盈富的公司介紹,他們除了在澳洲昆土蘭州建設度假村,還在當地開採地下水資源,成功找到優質水源生產高端礦泉水銷往中國。住在距離卓爾巴度假村抽水地點約5公里的牧場主人暨地主歐狄亞(Andrew O’Dea)表示,他對於區議會的決定感到「相當失望」。

歐狄亞的家族在當地畜牧已有約140年歷史,但受到乾旱影響,第5代的他被迫放棄幾乎所有牧群,如今只剩7頭母牛和1頭公牛。

歐狄亞說:「這的確令人相當難以承受,且(同意計畫)的時間點非常糟糕,因為我們已經沒有地表水可用。過去我們一直都能仰賴泉水和溪水。」

南原區市長杜比(Tracy Dobie)則捍衛區議會決定,表示在嚴格條件下卓爾巴度假村才得以將地下水裝瓶販售,且區議會也計畫動用聯邦政府的乾旱補助金,來協助支付鄉間家戶飲用水供應。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

※想要讓你的商品成為最夯、最多人討論的話題?網頁設計公司讓你強力曝光

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

雀巢砸逾620億 推動再生塑料使用

摘錄自2020年01月17日中央通訊社瑞士報導

瑞士食品大廠雀巢集團(Nestle)今天(17日)表示,將在5年內投資20億瑞士法郎(約新台幣621億元),以減少使用原始塑料,轉而採用食品級再生塑料。

法新社報導,雀巢也計劃投資新型永續包裝,以達到該公司的目標,也就是在2025年前全面使用可回收或可再利用的包裝材料。雀巢旗下品牌包含Nespresso咖啡、Vittel礦泉水和Smarties巧克力。

此外,雀巢發表聲明說,他們會在未來5年內,將原始塑料使用量降低1/3,且會撥出2億5000萬瑞士法郎作為創投基金,投資致力於廢棄物回收事業的新創公司。為打造再生塑料市場,雀巢計劃採購重達200萬公噸的食品級再生塑料,並撥出超過15億瑞士法郎,以支付從現在到2025年所需的材料附加費。雀巢執行長施奈德(Mark Schneider)在聲明中說:「最終不應有塑膠被丟入垃圾掩埋場,或成為廢棄物。」

綠色和平組織(Greenpeace)瑞士分部的維特里希(Matthias Wuthrich)表示,雀巢這項聲明「僅部分令人振奮」。他說:「這是朝正確方向所跨出的一步,但要結束當前危機,必須終止無用的塑膠生產作業,並須採用新的供應系統。」

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

※評比南投搬家公司費用收費行情懶人包大公開

農業和環保引發對立 德國兩派人馬街頭拉鋸

摘錄自2020年01月19日中央通訊社德國報導

德國農民與環保人士對壘加深,農民不滿新環保措施加重成本負擔,環保人士則抗議農業推升氣候變遷危機,兩邊的對立讓政治人物左右為難,也使得德國年度最大農業展蒙上陰影。

柏林一年一度「綠色週」貿易博覽會昨天(18日)開幕,德國農民選在當天展開一場名為「土地創造聯繫」(Land schafft Verbindung, LSV)活動,將數千輛牽引機開上全國各地城市街頭,藉此抗議政府施行更嚴格的農業法規。

德國最近推行的種種農業改革,包括在食品引進「動物福利標籤」、限制農藥使用以保護昆蟲等,都讓農民大喊吃不消,說政府新環保措施引發的成本都是農民在扛。他們也擔心新法規將導致收入大減,走上街頭據理力爭,高舉標語吶喊「別忘了是農民餵飽你們」、「沒有農場、沒有食物、沒有未來」。

農民昨天集體抗議後,今天輪到環保人士走上街頭。主辦單位說有約2萬7000名環保人士齊聚柏林地標布蘭登堡大門(Brandenburg Gate)附近,抗議他們口中的農業損害效應,並要求改變德國現行的務農方法。這場集會由環保團體「我們受夠了」(We are fed up)發起。氣候環保人士指稱近期的農業改革做得還不夠,現場另一邊站著抗議的農民,國會議員則被夾在中間。

農民和環保倡議者之間的鴻溝近幾年來有加深趨勢,這與學生帶領的「週五為未來而戰」(Fridays for Future)罷課抗暖化行動有關。環保人士今天的抗議行動自2011年以來年年登場,這個由綠色團體發起的活動要求全面性改革,以支持小農和對環境友善的農業。他們在網路上說:「農業加深暖化危機和社會衝突,我們必須加以阻止。」

農民組成的LSV抗議團體則自稱是相對於「我們受夠了」團體的反制力量,有憤怒的養蜂人將蜂蜜傾倒在政治人物大門前,也有生氣的農民走上街頭阻撓交通。農業部長克勒克納(Julia Kloeckner)16日呼籲對立的兩方要有妥協的胸襟。

綠黨共同領袖哈柏克(Robert Habeck)警告環保人士勿把氣候暖化歸咎在農民頭上,但也堅持說,拒絕改革並非社會前進之道,「減少對氣候和動物的保障,絕對不會是正確解答」。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

南投搬家費用,距離,噸數怎麼算?達人教你簡易估價知識!

升溫也列車禍原因! 研究:美國事故死亡人數隨暖化提高 且以年輕人、男性居多

環境資訊中心綜合外電;姜唯 編譯;林大利 審校

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置台北網頁設計,各種案例分享

泰國曼谷空品差 民眾抱怨政府無作為

摘錄自2020年1月21日公視報導

泰國曼谷近年來每到冬天,空氣品質就拉警報。曼谷的天空再度為霧霾籠罩,機車騎士紛紛戴上口罩,家庭主婦出門也不例外。

根據曼谷官方監測的數據,曼谷部分地區中午時段PM2.5濃度,飆升到每立方公尺 95微克,幾乎是安全標準的兩倍。官員表示這主要是受到逆溫現象的影響,也就是暖空氣將冷空氣困在地面附近,導致汽機車廢氣滯留且散不出去。泰國政府雖然已經開始管控汽車廢氣,必要時還派出無人機灑水,但霧鎖曼谷的情況依然每年上演。最新民調顯示,曼谷有八成一的民眾,認為政府改善空污沒有效率。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

南投搬家前需注意的眉眉角角,別等搬了再說!

智慧口罩多功能 抵抗空污新利器

摘錄自2020年1月21日公視報導

空污對人體的危害越來越受到關注。現在有業者推出了一款智慧口罩,裡面有風扇的裝置,能即時偵測身邊懸浮微粒的指數,還可以跟手機連線,成為新一代對抗空污的利器。

荷蘭一家新創公司在今年的消費性電子大展上,就推出了最新的智慧口罩。這款智慧口罩配備了及時的懸浮微粒偵測系統,搭配LED警示光源,也內建再生材的高品質濾心,可重複清洗使用,使用時效長達兩年,更可以透過USB充電,讓配戴者有效避開空氣污染源。

艾戴爾說:「首先我們是針對氣體的污染感應,以及粉塵微粒的感應,同時也能跟手機連線。我們的目標就是有一天能透過足夠的資訊,建立有效的空污地圖。當你從A點走到B點,你不需要走最短或最快的路線,而是走最少污染的路線。」

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!