003.Kubernetes二進制部署準備

一 前置準備

1.1 前置條件

相應的充足資源的Linux服務器;

設置相應的主機名,參考命令:

 1 hostnamectl set-hostname k8smaster

Mac及UUID唯一;

若未關閉防火牆則建議放通相應端口,如下:

Master節點——






規則

方向

端口範圍

作用

使用者

TCP

Inbound

6443*

Kubernetes API server

All

TCP

Inbound

2379-2380

etcd server client API

kube-apiserver, etcd

TCP

Inbound

10250

Kubelet API

Self, Control plane

TCP

Inbound

10251

kube-scheduler

Self

TCP

Inbound

10252

kube-controller-manager

Self

Worker 節點——

規則

方向

端口範圍

作用

使用者

TCP

Inbound

10250

Kubelet API

Self, Control plane

TCP

Inbound

30000-32767

NodePort Services**

All


其他更多前置準備見:

二 主要組件

2.1 核心組件

  • etcd:保存了整個集群的狀態;
  • apiserver:提供了資源操作的唯一入口,並提供認證、授權、訪問控制、API註冊和發現等機制;
  • controller manager:負責維護集群的狀態,比如故障檢測、自動擴展、滾動更新等;
  • scheduler:負責資源的調度,按照預定的調度策略將Pod調度到相應的機器上;
  • kubelet:負責維護容器的生命周期,同時也負責Volume(CVI)和網絡(CNI)的管理;
  • Container runtime:負責鏡像管理以及Pod和容器的真正運行(CRI);
  • kube-proxy:負責為Service提供cluster內部的服務發現和負載均衡。

2.2 非核心組件

  • kube-dns:負責為整個集群提供DNS服務;
  • Ingress Controller:為服務提供外網入口;
  • Heapster:提供資源監控;
  • Dashboard:提供GUI;
  • Federation:集群聯邦提供跨可用區的集群;
  • Fluentd-elasticsearch:提供集群日誌採集、存儲與查詢。

延伸1:對master節點服務組件的理解:

Master節點上面主要由四個模塊組成:APIServer,schedule,controller-manager,etcd。

APIServer: APIServer負責對外提供RESTful的kubernetes API的服務,它是系統管理指令的統一接口,任何對資源的增刪該查都要交給APIServer處理后再交給etcd,如架構圖中所示,kubectl(Kubernetes提供的客戶端工具,該工具內部就是對Kubernetes API的調用)是直接和APIServer交互的。

schedule: schedule負責調度Pod到合適的Node上,如果把scheduler看成一個黑匣子,那麼它的輸入是pod和由多個Node組成的列表,輸出是Pod和一個Node的綁定,即將這個pod部署到這個Node上。Kubernetes目前提供了調度算法,但是同樣也保留了接口,用戶可以根據自己的需求定義自己的調度算法。

controller manager: 如果APIServer做的是前台的工作的話,那麼controller manager就是負責後台的。每一個資源都對應一個控制器。而control manager就是負責管理這些控制器的,比如我們通過APIServer創建了一個Pod,當這個Pod創建成功后,APIServer的任務就算完成了。而後面保證Pod的狀態始終和我們預期的一樣的重任就由controller manager去保證了。

etcd:etcd是一個高可用的鍵值存儲系統,kubernetes使用它來存儲各個資源的狀態,從而實現了Restful的API。

延伸2:對master節點服務組件的理解:

每個Node節點主要由三個模板組成:kubelet、kube-proxy、runtime。

runtime:runtime指的是容器運行環境,目前Kubernetes支持docker和rkt兩種容器。

kube-proxy: 該模塊實現了kubernetes中的服務發現和反向代理功能。kube-proxy支持TCP和UDP連接轉發,默認基於Round Robin算法將客戶端流量轉發到與service對應的一組後端pod。服務發現方面,kube-proxy使用etcd的watch機制,監控集群中service和endpoint對象數據的動態變化,並且維護一個service到endpoint的映射關係,從而保證了後端pod的IP變化不會對訪問者造成影響。另外,kube-proxy還支持session affinity。

kublet:kublet是Master在每個Node節點上面的agent,是Node節點上面最重要的模塊,它負責維護和管理該Node上的所有容器,但是如果容器不是通過kubernetes創建的,它並不會管理。本質上,它負責使Pod的運行狀態與期望的狀態一致。

三 部署規劃

3.1 節點規劃

節點

IP

類型

運行服務

k8smaster01 172.24.8.71 Kubernetes master節點 docker、etcd、kube-apiserver、kube-scheduler、kube-controller-manager、kubectl、kubelet、kube-nginx、flannel
k8smaster02 172.24.8.72 Kubernetes master節點 docker、etcd、kube-apiserver、kube-scheduler、kube-controller-manager、kubectl、 kubelet、kube-nginx、flannel
k8smaster03 172.24.8.73 Kubernetes master節點 docker、etcd、kube-apiserver、kube-scheduler、kube-controller-manager、kubectl、 kubelet、kube-nginx、flannel
k8snode01 172.24.8.74 Kubernetes node節點1 docker、etcd、kubelet、proxy、flannel
k8snode03 172.24.8.75 Kubernetes node節點2 docker、etcd、kubelet、proxy、flannel

提示:本實驗使用三節點master部署,從而實現master的高可用。

3.2 組件及版本

  • Kubernetes 1.14.2
  • Docker 18.09.6-ce
  • Etcd 3.3.13
  • Flanneld 0.11.0
  • 插件:
    • Coredns
    • Dashboard
    • Metrics-server
    • EFK (elasticsearch、fluentd、kibana)
  • 鏡像倉庫:
    • docker registry
    • harbor

3.3 組件策略

kube-apiserver:

  • 使用節點本地 nginx 4 層透明代理實現高可用;
  • 關閉非安全端口 8080 和匿名訪問;
  • 在安全端口 6443 接收 https 請求;
  • 嚴格的認證和授權策略 (x509、token、RBAC);
  • 開啟 bootstrap token 認證,支持 kubelet TLS bootstrapping;
  • 使用 https 訪問 kubelet、etcd,加密通信;

kube-controller-manager:

  • 3 節點高可用;
  • 關閉非安全端口,在安全端口 10252 接收 https 請求;
  • 使用 kubeconfig 訪問 apiserver 的安全端口;
  • 自動 approve kubelet 證書籤名請求 (CSR),證書過期后自動輪轉;
  • 各 controller 使用自己的 ServiceAccount 訪問 apiserver;

kube-scheduler:

  • 3 節點高可用;
  • 使用 kubeconfig 訪問 apiserver 的安全端口;

kubelet:

  • 使用 kubeadm 動態創建 bootstrap token,而不是在 apiserver 中靜態配置;
  • 使用 TLS bootstrap 機制自動生成 client 和 server 證書,過期后自動輪轉;
  • 在 KubeletConfiguration 類型的 JSON 文件配置主要參數;
  • 關閉只讀端口,在安全端口 10250 接收 https 請求,對請求進行認證和授權,拒絕匿名訪問和非授權訪問;
  • 使用 kubeconfig 訪問 apiserver 的安全端口;

kube-proxy:

  • 使用 kubeconfig 訪問 apiserver 的安全端口;
  • 在 KubeProxyConfiguration 類型的 JSON 文件配置主要參數;
  • 使用 ipvs 代理模式;

集群插件:

  • DNS:使用功能、性能更好的 coredns;
  • Dashboard:支持登錄認證;
  • Metric:metrics-server,使用 https 訪問 kubelet 安全端口;
  • Log:Elasticsearch、Fluend、Kibana;
  • Registry 鏡像庫:docker-registry、harbor。

四 其他準備

4.1 手動添加解析

注意:以下4.1至4.7步驟可通過如下腳本快速實現:

  1 [root@k8smaster01 ~]# vi k8sinit.sh
  2 # Modify Author: xhy
  3 # Modify Date: 2019-06-23 22:19
  4 # Version:
  5 #***************************************************************#
  6 # Initialize the machine. This needs to be executed on every machine.
  7 
  8 # Add host domain name.
  9 cat >> /etc/hosts << EOF
 10 172.24.8.71 k8smaster01
 11 172.24.8.72 k8smaster02
 12 172.24.8.73 k8smaster03
 13 172.24.8.74 k8snode01
 14 172.24.8.75 k8snode02
 15 EOF
 16 
 17 # Add docker user
 18 useradd -m docker
 19 
 20 # Disable the SELinux.
 21 sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config
 22 
 23 # Turn off and disable the firewalld.
 24 systemctl stop firewalld
 25 systemctl disable firewalld
 26 
 27 # Modify related kernel parameters & Disable the swap.
 28 cat > /etc/sysctl.d/k8s.conf << EOF
 29 net.ipv4.ip_forward = 1
 30 net.bridge.bridge-nf-call-ip6tables = 1
 31 net.bridge.bridge-nf-call-iptables = 1
 32 net.ipv4.tcp_tw_recycle = 0
 33 vm.swappiness = 0
 34 vm.overcommit_memory = 1
 35 vm.panic_on_oom = 0
 36 net.ipv6.conf.all.disable_ipv6 = 1
 37 EOF
 38 sysctl -p /etc/sysctl.d/k8s.conf >&/dev/null
 39 swapoff -a
 40 sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
 41 modprobe br_netfilter
 42 
 43 # Add ipvs modules
 44 cat > /etc/sysconfig/modules/ipvs.modules <<EOF
 45 #!/bin/bash
 46 modprobe -- ip_vs
 47 modprobe -- ip_vs_rr
 48 modprobe -- ip_vs_wrr
 49 modprobe -- ip_vs_sh
 50 modprobe -- nf_conntrack_ipv4
 51 EOF
 52 chmod 755 /etc/sysconfig/modules/ipvs.modules
 53 bash /etc/sysconfig/modules/ipvs.modules
 54 
 55 # Install rpm
 56 yum install -y conntrack ntpdate ntp ipvsadm ipset jq iptables curl sysstat libseccomp wget
 57 
 58 # Create k8s directory $$ Add system PATH
 59 mkdir -p  /opt/k8s/{bin,work} /etc/{kubernetes,etcd}/cert
 60 echo 'PATH=/opt/k8s/bin:$PATH' >>/root/.bashrc
 61 source /root/.bashrc
 62 
 63 # Reboot the machine.
 64 reboot
  1 [root@k8smaster01 ~]# cat <<EOF >> /etc/hosts
  2 172.24.8.71 k8smaster01
  3 172.24.8.72 k8smaster02
  4 172.24.8.73 k8smaster03
  5 172.24.8.74 k8snode01
  6 172.24.8.75 k8snode02
  7 EOF

提示:所有節點均建議如上操作。

4.2 添加docker賬戶

  1 [root@k8smaster01 ~]# useradd -m docker

提示:所有節點均建議如上操作。

4.3 關閉SELinux

  1 [root@k8smaster01 ~]# setenforce 0
  2 [root@k8smaster01 ~]# sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config

4.4 修正iptables

  1 [root@k8smaster01 ~]# systemctl stop firewalld
  2 [root@k8smaster01 ~]# systemctl disable firewalld			#關閉防火牆
  3 [root@k8smaster01 ~]# cat <<EOF >> /etc/sysctl.d/k8s.conf
  4 net.bridge.bridge-nf-call-ip6tables = 1
  5 net.bridge.bridge-nf-call-iptables = 1
  6 net.ipv4.ip_forward = 1
  7 EOF
  8 [root@k8smaster01 ~]# modprobe br_netfilter
  9 [root@k8smaster01 ~]# sysctl -p /etc/sysctl.d/k8s.conf

提示:所有節點均建議如上操作。

4.5 關閉swap

  1 [root@k8smaster01 ~]# sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
  2 [root@k8smaster01 ~]# echo "vm.swappiness = 0" >> /etc/sysctl.d/k8s.conf	#禁止使用 swap 空間,只有當系統 OOM 時才允許使用它
  3 [root@k8smaster01 ~]# sysctl -p /etc/sysctl.d/k8s.conf

4.6 其他調整

  1 [root@k8smaster01 ~]# cat <<EOF >> /etc/sysctl.d/k8s.conf
  2 vm.overcommit_memory = 1						# 不檢查物理內存是否夠用
  3 vm.panic_on_oom = 0							# 開啟 OOM
  4 net.ipv6.conf.all.disable_ipv6 = 1					# 關閉 IPV6
  5 EOF
  6 [root@k8smaster01 ~]# sysctl -p /etc/sysctl.d/k8s.conf
  7 [root@k8smaster01 ~]# mkdir -p  /opt/k8s/{bin,work} /etc/{kubernetes,etcd}/cert	#創建相應目錄
  8 [root@k8smaster01 ~]# yum install -y conntrack ntpdate ntp ipvsadm ipset jq iptables curl sysstat libseccomp wget

提示:必須關閉 tcp_tw_recycle,否則和 NAT 衝突,會導致服務不通;

關閉 IPV6,防止觸發 docker BUG。

4.7 加載IPVS

pod的負載均衡是用kube-proxy來實現的,實現方式有兩種,一種是默認的iptables,一種是ipvs,相對iptables,ipvs有更好的性能。且當前ipvs已經加入到了內核的主幹。

為kube-proxy開啟ipvs的前提需要加載以下的內核模塊:

  • ip_vs
  • ip_vs_rr
  • ip_vs_wrr
  • ip_vs_sh
  • nf_conntrack_ipv4
  1 [root@k8smaster01 ~]# cat > /etc/sysconfig/modules/ipvs.modules <<EOF
  2 #!/bin/bash
  3 modprobe -- ip_vs
  4 modprobe -- ip_vs_rr
  5 modprobe -- ip_vs_wrr
  6 modprobe -- ip_vs_sh
  7 modprobe -- nf_conntrack_ipv4
  8 EOF
  9 [root@k8smaster01 ~]# chmod 755 /etc/sysconfig/modules/ipvs.modules
 10 [root@k8smaster01 ~]# bash /etc/sysconfig/modules/ipvs.modules
 11 [root@k8smaster01 ~]# lsmod | grep -e ip_vs -e nf_conntrack_ipv4
 12 [root@k8smaster01 ~]# yum -y install ipvsadm

提示:所有節點均建議如上操作。

為了更好的管理和查看ipvs,可安裝相應的管理工具《002.LVS管理工具的安裝與使用》。

五 環境準備

5.1 配置免秘鑰

為了更方便遠程分發文件和執行命令,本實驗配置master節點到其它節點的 ssh 信任關係。

  1 [root@k8smaster01 ~]# ssh-keygen -f ~/.ssh/id_rsa -N ''
  2 [root@k8smaster01 ~]# ssh-copy-id -i ~/.ssh/id_rsa.pub root@k8smaster01
  3 [root@k8smaster01 ~]# ssh-copy-id -i ~/.ssh/id_rsa.pub root@k8smaster02
  4 [root@k8smaster01 ~]# ssh-copy-id -i ~/.ssh/id_rsa.pub root@k8smaster03
  5 [root@k8smaster01 ~]# ssh-copy-id -i ~/.ssh/id_rsa.pub root@k8snode01
  6 [root@k8smaster01 ~]# ssh-copy-id -i ~/.ssh/id_rsa.pub root@k8snode02

提示:此操作僅需要在master節點操作。

5.2 分發集群配置參數腳本

後續使用的環境變量都定義在文件 environment.sh 中,同時拷貝到所有節點的 /opt/k8s/bin 目錄:

  1 #!/usr/bin/bash
  2 
  3 # 生成 EncryptionConfig 所需的加密 key
  4 export ENCRYPTION_KEY=$(head -c 32 /dev/urandom | base64)
  5 
  6 # 集群 MASTER 機器 IP 數組
  7 export MASTER_IPS=(172.24.8.71 172.24.8.72 172.24.8.73)
  8 
  9 # 集群 MASTER IP 對應的主機名數組
 10 export MASTER_NAMES=(k8smaster01 k8smaster02 k8smaster03)
 11 
 12 # 集群 NODE 機器 IP 數組
 13 export NODE_IPS=(172.24.8.74 172.24.8.75)
 14 
 15 # 集群 NODE IP 對應的主機名數組
 16 export NODE_NAMES=(k8snode01 k8snode02)
 17 
 18 # 集群所有機器 IP 數組
 19 export ALL_IPS=(172.24.8.71 172.24.8.72 172.24.8.73 172.24.8.74 172.24.8.75)
 20 
 21 # 集群所有IP 對應的主機名數組
 22 export ALL_NAMES=(k8smaster01 k8smaster02 k8smaster03 k8snode01 k8snode02)
 23 
 24 # etcd 集群服務地址列表
 25 export ETCD_ENDPOINTS="https://172.24.8.71:2379,https://172.24.8.72:2379,https://172.24.8.73:2379"
 26 
 27 # etcd 集群間通信的 IP 和端口
 28 export ETCD_NODES="k8smaster01=https://172.24.8.71:2380,k8smaster02=https://172.24.8.72:2380,k8smaster03=https://172.24.8.73:2380"
 29 
 30 # kube-apiserver 的反向代理(kube-nginx)地址端口
 31 export KUBE_APISERVER="https://127.0.0.1:8443"
 32 
 33 # 節點間互聯網絡接口名稱
 34 export IFACE="eth0"
 35 
 36 # etcd 數據目錄
 37 export ETCD_DATA_DIR="/data/k8s/etcd/data"
 38 
 39 # etcd WAL 目錄,建議是 SSD 磁盤分區,或者和 ETCD_DATA_DIR 不同的磁盤分區
 40 export ETCD_WAL_DIR="/data/k8s/etcd/wal"
 41 
 42 # k8s 各組件數據目錄
 43 export K8S_DIR="/data/k8s/k8s"
 44 
 45 # docker 數據目錄
 46 export DOCKER_DIR="/data/k8s/docker"
 47 
 48 ## 以下參數一般不需要修改
 49 
 50 # TLS Bootstrapping 使用的 Token,可以使用命令 head -c 16 /dev/urandom | od -An -t x | tr -d ' ' 生成
 51 BOOTSTRAP_TOKEN="41f7e4ba8b7be874fcff18bf5cf41a7c"
 52 
 53 # 最好使用 當前未用的網段 來定義服務網段和 Pod 網段
 54 
 55 # 服務網段,部署前路由不可達,部署後集群內路由可達(kube-proxy 保證)
 56 SERVICE_CIDR="10.254.0.0/16"
 57 
 58 # Pod 網段,建議 /16 段地址,部署前路由不可達,部署後集群內路由可達(flanneld 保證)
 59 CLUSTER_CIDR="172.30.0.0/16"
 60 
 61 # 服務端口範圍 (NodePort Range)
 62 export NODE_PORT_RANGE="30000-32767"
 63 
 64 # flanneld 網絡配置前綴
 65 export FLANNEL_ETCD_PREFIX="/kubernetes/network"
 66 
 67 # kubernetes 服務 IP (一般是 SERVICE_CIDR 中第一個IP)
 68 export CLUSTER_KUBERNETES_SVC_IP="10.254.0.1"
 69 
 70 # 集群 DNS 服務 IP (從 SERVICE_CIDR 中預分配)
 71 export CLUSTER_DNS_SVC_IP="10.254.0.2"
 72 
 73 # 集群 DNS 域名(末尾不帶點號)
 74 export CLUSTER_DNS_DOMAIN="cluster.local"
 75 
 76 # 將二進制目錄 /opt/k8s/bin 加到 PATH 中
 77 export PATH=/opt/k8s/bin:$PATH
  1 [root@k8smaster01 ~]# source environment.sh
  2 [root@k8smaster01 ~]# for all_ip in ${ALL_IPS[@]}
  3   do
  4     echo ">>> ${all_ip}"
  5     scp environment.sh root@${all_ip}:/opt/k8s/bin/
  6     ssh root@${all_ip} "chmod +x /opt/k8s/bin/*"
  7   done

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

【其他文章推薦】

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

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

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

Abp vNext 自定義 Ef Core 倉儲引發異常

問題

在使用自定義 Ef Core 倉儲和 ABP vNext 注入的默認倉儲時,通過兩個 Repository 進行 Join 操作,提示 Cannot use multiple DbContext instances within a single query execution. Ensure the query uses a single context instance. 。這個異常信息翻譯成中文的大概意思就是,你不能使用兩個 DbContext 裏面的 DbSet 進行 Join 查詢。

如果將自定義倉儲改為 IRepository<TEntity,TKey> 進行注入,是可以與 _courseRepostory 進行關聯查詢的。

我在 XXXEntityFrameworkCoreModule 的配置,以及自定義倉儲 EfCoreStudentRepository 代碼如下。

XXXEntityFrameworkCoreModule 代碼:

public class XXXEntityFrameworkCoreModule : AbpModule
{
    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        context.Services.AddAbpDbContext<XXXDbContext>(op =>
        {
            op.AddDefaultRepositories();
        });
        
        Configure<AbpDbContextOptions>(op => op.UsePostgreSql());
    }
}

EfCoreStudentRepository 代碼:

public class EfCoreStudentRepository : EfCoreRepository<IXXXDbContext, Student, long>, IStudentRepository
{
    public EfCoreStudentRepository(IDbContextProvider<IXXXDbContext> dbContextProvider) : base(dbContextProvider)
    {
    }

    public Task<int> GetCountWithStudentlIdAsync(long studentId)
    {
        return DbSet.CountAsync(x=>x.studentId == studentId);
    }
}

原因

原因在異常信息已經說得十分清楚了,這裏我們需要了解兩個問題。

  1. 什麼原因導致兩個倉儲內部的 DbContext 不一致?
  2. 為什麼 ABP vNext 自己實現的倉儲能夠進行關聯查詢呢?

首先我們得知道,倉儲內部的 DbContext是怎麼獲取的。我們的自定義倉儲都會繼承 EfCoreRepository ,而這個倉儲是實現了 IQuerable<T> 接口的,最終它會通過一個 IDbContextProvider<TDbContext> 獲得一個可用的 DbContext 。

public class EfCoreRepository<TDbContext, TEntity> : RepositoryBase<TEntity>, IEfCoreRepository<TEntity>
    where TDbContext : IEfCoreDbContext
    where TEntity : class, IEntity
{
    public virtual DbSet<TEntity> DbSet => DbContext.Set<TEntity>();

    DbContext IEfCoreRepository<TEntity>.DbContext => DbContext.As<DbContext>();

    // 這裏可以看到,是通過 IDbContextProvider 來獲得 DbContext 的。
    protected virtual TDbContext DbContext => _dbContextProvider.GetDbContext();

    protected virtual AbpEntityOptions<TEntity> AbpEntityOptions => _entityOptionsLazy.Value;

    private readonly IDbContextProvider<TDbContext> _dbContextProvider;
    private readonly Lazy<AbpEntityOptions<TEntity>> _entityOptionsLazy;

    // ... 其他代碼。
}

下面就是 IDbContextProvider<TDbContext> 內部的核心代碼:

public class UnitOfWorkDbContextProvider<TDbContext> : IDbContextProvider<TDbContext> where TDbContext : IEfCoreDbContext
{
    private readonly IUnitOfWorkManager _unitOfWorkManager;
    private readonly IConnectionStringResolver _connectionStringResolver;

    // ... 其他代碼。

    public TDbContext GetDbContext()
    {
        var unitOfWork = _unitOfWorkManager.Current;
        if (unitOfWork == null)
        {
            throw new AbpException("A DbContext can only be created inside a unit of work!");
        }

        var connectionStringName = ConnectionStringNameAttribute.GetConnStringName<TDbContext>();
        var connectionString = _connectionStringResolver.Resolve(connectionStringName);

        // 會構造一個 Key,而這個 Key 剛好是泛型類型的 FullName。
        var dbContextKey = $"{typeof(TDbContext).FullName}_{connectionString}";

        // 內部是從一個字典當中,根據 dbContextKey 獲取 DbContext。如果不存在的話則調用工廠方法創建一個新的 DbContext。
        var databaseApi = unitOfWork.GetOrAddDatabaseApi(
            dbContextKey,
            () => new EfCoreDatabaseApi<TDbContext>(
                CreateDbContext(unitOfWork, connectionStringName, connectionString)
            ));

        return ((EfCoreDatabaseApi<TDbContext>)databaseApi).DbContext;
    }

    // ... 其他代碼。
}

通過以上代碼我們就可以知道,ABP vNext 在倉儲的內部是通過 IDbContextProvider<TDbContext> 中的 TDbContext 泛型,來確定是否構建一個新的 DbContext 對象。

不論是 ABP vNext 針對 IRepository<TEntity,TKey> ,還是我們自己實現的自定義倉儲,它們最終的實現都是基於 EfCoreRepository<TDbContext,TEntity,TKey> 的。而我們 IDbContextProvider<TDbContext> 的泛型,也是這個倉儲基類提供的,後者的 TDbContext 就是前者的泛型參數。

所以當我們在模塊添加 DbContext 的過城中,只要調用了 AddDefaultRepositories() 方法,ABP vNext 就會遍歷你提供的 TDbContext 所定義的實體,然後為這些實體建立默認的倉儲。

在注入倉儲的時候,找到了獲得默認倉儲實現類型的方法,可以看到這裏它使用的是 DefaultRepositoryDbContextType 作為默認的 TDbContext 類型。

protected virtual Type GetDefaultRepositoryImplementationType(Type entityType)
{
    var primaryKeyType = EntityHelper.FindPrimaryKeyType(entityType);

    // 重點在於構造倉儲類型時,傳遞的 Options.DefaultRepositoryDbContextType 參數,這個參數就是後面 EfCoreRepository 的 TDbContext 泛型。
    if (primaryKeyType == null)
    {
        return Options.SpecifiedDefaultRepositoryTypes
            ? Options.DefaultRepositoryImplementationTypeWithoutKey.MakeGenericType(entityType)
            : GetRepositoryType(Options.DefaultRepositoryDbContextType, entityType);
    }

    return Options.SpecifiedDefaultRepositoryTypes
        ? Options.DefaultRepositoryImplementationType.MakeGenericType(entityType, primaryKeyType)
        : GetRepositoryType(Options.DefaultRepositoryDbContextType, entityType, primaryKeyType);
}

最後我發現這個就是在模塊調用 AddAbpContext<TDbContext> 所提供的泛型參數。

public abstract class AbpCommonDbContextRegistrationOptions : IAbpCommonDbContextRegistrationOptionsBuilder
{
    // ... 其他代碼

    protected AbpCommonDbContextRegistrationOptions(Type originalDbContextType, IServiceCollection services)
    {
        OriginalDbContextType = originalDbContextType;
        Services = services;
        DefaultRepositoryDbContextType = originalDbContextType;
        CustomRepositories = new Dictionary<Type, Type>();
        ReplacedDbContextTypes = new List<Type>();
    }

    // ... 其他代碼
}

public class AbpDbContextRegistrationOptions : AbpCommonDbContextRegistrationOptions, IAbpDbContextRegistrationOptionsBuilder
{
    public Dictionary<Type, object> AbpEntityOptions { get; }

    public AbpDbContextRegistrationOptions(Type originalDbContextType, IServiceCollection services)
        : base(originalDbContextType, services) // 之類調用的就是上面的構造方法。
    {
        AbpEntityOptions = new Dictionary<Type, object>();
    }
}

public static class AbpEfCoreServiceCollectionExtensions
{
    public static IServiceCollection AddAbpDbContext<TDbContext>(
        this IServiceCollection services, 
        Action<IAbpDbContextRegistrationOptionsBuilder> optionsBuilder = null)
        where TDbContext : AbpDbContext<TDbContext>
    {
        // ... 其他代碼。
        
        var options = new AbpDbContextRegistrationOptions(typeof(TDbContext), services);

        // ... 其他代碼。

        return services;
    }
}

所以,我們的默認倉儲的 dbContextKey 是 XXXDbContext,我們的自定義倉儲繼承 EfCoreRepository<IXXXDbContext,TEntity,TKey> ,所以它的 dbContextKey 就是 IXXXDbContext 。所以自定義倉儲獲取到的 DbContext 就與自定義倉儲的不一致了,從而提示上述異常。

解決

找到自定自定義倉儲的定義,修改它 EfCoreReposiotry<TDbContext,TEntity,TKey> 的 TDbContext 泛型參數,變更為 XXXDbContext 即可。

public class EfCoreStudentRepository : EfCoreRepository<XXXDbContext, Student, long>, IStudentRepository
{
    public EfCoreStudentRepository(IDbContextProvider<XXXDbContext> dbContextProvider) : base(dbContextProvider)
    {
    }

    public Task<int> GetCountWithStudentlIdAsync(long studentId)
    {
        return DbSet.CountAsync(x=>x.studentId == studentId);
    }
}

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

【其他文章推薦】

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

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

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

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

科學家發現新型態鈾 恐影響核廢料處理計畫

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

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

【其他文章推薦】

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

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

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

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

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

澳洲野火不止 維州熱浪祭禁火令 擬照辦跨年煙火秀

摘錄自2019年12月30日中央通訊社報導

澳洲野火肆虐,重創當地生態環境及空氣品質,已逾26萬人連署,建議取消知名的雪梨跨年煙火秀,以免助長空氣污染,把錢省下來幫助受災農民及消防員等,不過,雪梨市長克洛弗.摩爾(Clover Moore)已煙火秀照舊,且據報導,高達10萬支煙火都已裝船開運,其中有8成來自中國。

綜合媒體報導,雪梨是全球最早迎接新年的大城市之一,跨年煙火秀更是全球慶祝跨年的重點戲之一,去(2018)年就花了580萬澳元(約1.2億元台幣),今年打算花650萬澳元(約1.36億台幣)來辦跨年煙火秀,但今年正值澳洲發生數十年來最嚴重的野火災難,致農損嚴重,截至目前並未撲滅,致使澳洲民眾在網上連署,建議當局取消今年跨年煙火秀。

不過當局並不打算取消,女市長摩爾並表示,若是取消,可能重創雪梨商家們,也會毀了數以萬計前來雪梨參加跨年活動人們的計劃。

即使如此,這場煙火秀是否在最後喊停,還在未定之天,因為,澳洲野火未停,仍有接近100個火場火勢仍未撲滅,雪梨所屬的新南威爾斯省的災情最嚴重,且位於雪梨西南面的巴爾莫勒爾鎮幾乎全毀,許多公路仍然封閉;且產生的空氣污染已經形成有毒煙霧,籠罩雪梨及其他主要城市。

由於East Gippsland的森林火災不斷升級,加上熱浪來襲,預計今天氣溫可能升高到44度,維多利亞州當局已在昨天(29日)下令,全面撤離Goongerah和Martins Creek地區居民,今天更將全州實行禁火令,嚴禁人們在戶外用火。

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

【其他文章推薦】

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

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

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

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

菲擬重啟核電 地震帶問題未解

摘錄自2019年12月27日自由時報報導

菲律賓能源部長庫希(Alfonso Cusi)接受英國金融時報訪問表示,為了解決未來可能出現的能源匱乏問題,菲律賓已經與國際原子能總署(IAEA)合作,努力達成聯合國監管機構要求的安全條件,擬重啟已被擱置許久的核電廠計畫。

菲律賓前獨裁領袖馬可仕擔任總統時,曾在首都馬尼拉附近的巴丹半島建造核電廠,因民眾反彈聲浪,巴丹核電廠計畫於1986年,被時任總統柯拉蓉.艾奎諾擱置。

菲律賓西邊的南海雖然富含石油與天然氣資源,但因主權爭議使菲國無法開採。庫希表示,菲國需要穩固、可靠、負擔得起的能源,而核能正好符合上述條件。菲國總統杜特蒂今年十月訪問莫斯科時,與俄方簽署合作意向書。庫希說,為重啟核電廠,菲國考慮和南韓合作,也不排除向原始建造商美國西屋電氣尋求協助,但一切都尚未確定。

評論家指出,巴丹核電廠有雙重風險,它不只選址於環太平洋地震帶,甚至選在一座休眠火山上,核能污染的危險性恐因該地的地質環境而惡化。對此,菲國能源部去年曾發表文章澄清,巴丹核電廠並非選址於火山口,且專家研判,像日本福島震災一樣芮氏規模九的強震,幾乎不可能在菲國發生。

庫希表示,在所有相關法案通過後,尚需七至八年才能完成核電廠計畫,在這期間,他們也會持續尋找其他可用能源,例如油、煤、天然氣、再生能源等。

由於核電廠造價不菲,且菲律賓已有其他大型建設延宕,不少分析師懷疑菲國是否有能力執行核電廠計畫。能源諮詢公司伍德麥肯茲(Wood Mackenzie)的亞太研究主管哈伍德(Andrew Harwood)指出,重啟巴丹核電廠需要巨額資金,使用煤與其他再生能源是最便宜且可行方法。

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

【其他文章推薦】

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

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

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

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

全球最長壽黑犀牛 57歲壽終正寢

摘錄自2019年12月28日中央通訊社綜合報導

坦尚尼亞保護區管理局指出,據信是全球最長壽的一頭雌黑犀牛昨天(27日)在恩戈羅恩戈羅保護區壽終正寢,享壽57歲。

恩戈羅恩戈羅保護區管理局(Ngorongoro Conservation Area Authority)28日發表聲說,名為佛斯塔(Fausta)的這頭雌黑犀牛,於12月27日在保護區內據信因自然原因死亡,牠生前絕大部分時間都是在野外生活。

恩戈羅恩戈羅保護區管理局估計,野生犀牛的壽命介於37到43歲間,圈養犀牛則能活到50歲以上。聲明指出,紀錄顯示,佛斯塔較全球任何其他犀牛都更長壽,在恩戈羅恩戈羅放養超過54年,2016年才移至庇護區。

聲明又說:「三蘭港大學(University of Dar Es Salaam)一位科學家於1965年首度在恩戈羅恩戈羅火山口發現佛斯塔,當時牠的年齡介於3至4歲間。繼多次遭鬣狗攻擊且嚴重受傷後,牠的健康狀況於2016年開始惡化,我們不得不把牠置於圈養狀態。」

而全球最長壽的白犀牛,則是55歲的雌南方白犀牛沙納(Sana),於2017年在圈養地法國奇幻星球動物園(La Planete Sauvage Zoological park)死亡。

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

【其他文章推薦】

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

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

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

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

來自衣服與塑袋 英國倫敦微塑料沉積嚴重

摘錄自2019年12月28日中央通訊社綜合報導

英國「衛報」報導,有研究發現,城市居民會吸收空氣中傾洩而下的微塑料污染物,目前記錄到微塑料沉積最嚴重的城市為英國倫敦。吸入或吃進細小塑膠微粒對人體健康的衝擊仍不明,專家呼籲有必要即刻研究以評估相關風險。

這份研究目前只評估4個城市,但4個地方的空氣全都有微塑料的蹤影。科學家相信,由於衣服與包裝袋等微塑料的源頭四處可見,世界每個城市的空氣應都有被微塑料污染。

這份刊登於「國際環境」(Environment International)期刊的研究指出,每年約新增3.35億公噸原始塑料,大多流入自然環境。

研究人員在倫敦市中心一棟9層樓的建物屋頂蒐集飄落的微塑料,在全部8個樣本裡都有發現,沉積率從每天每平方公尺575片到1008片不等,且從中確認出15種不同的塑料。大部分的微塑料是壓克力纖維,極可能來自人們的衣服。只有8%是塑膠微粒,當中大部分為聚苯乙烯、聚乙烯,這兩者皆為常用的食品包裝材料。

倫敦的微塑料沉積率是中國東莞的20倍、法國巴黎的7倍、將近德國漢堡的3倍。研究員目前仍不知道各地沉積率差異的原因,不同的實驗方式有可能是原因之一。

倫敦空氣裡的微塑料含量震驚了科學家。帶領這項研究的倫敦國王學院(King’s College London)專家萊特(Stephanie Wright)說:「我們發現高含量的微塑料,遠高於先前披露的數據。但世界所有城市應該都會有類似狀況」。

在倫敦市中心採集到的塑膠微粒介於0.02毫米至0.5毫米之間,這些微粒大到在吸入時會停留在呼吸道,並順著唾液被吞入。更小的粒子會被吸入肺部和血液,對健康造成最大的潛在危害。

報導指出,交通和工業排放的污染物對人體的嚴重危害眾所皆知,2019年初一份綜合性的全球評估指出,空污可能會損害人體每一個器官,甚至每一個細胞。但目前仍然不知道從空氣吸進、從飲食吃進塑膠微粒對人體的潛在衝擊程度;根據其他研究,人們平均每年吃下至少5萬個塑膠微粒。

德國「艾佛瑞德維根納極地海洋研究所」(Alfred Wegener Institute for Polar and Marine Research)專家柏格曼(Melanie Bergmann)表示,對微塑料污染潛藏的健康危害進行更多研究非常重要,「我們目前並不知道,吸入人體的微塑料,有多少會滲入肺部深處」。

萊特說,要想減少微塑料,就要改變使用塑膠及處理塑膠的方式,「你沒有辦法清光它們,所以該是從源頭來遏止了」。

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

【其他文章推薦】

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

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

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

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

非洲豬瘟肆虐 越南求助美國與荷蘭合製疫苗

摘錄自2019年12月28日中央通訊社報導

越南非洲豬瘟疫情升溫,嚴重打擊養豬業,造成境內豬肉供應短缺。越南農業機構表示,將與美國與荷蘭合作研製非洲豬瘟疫苗,同時擴大豬肉進口以彌補境內缺口,鼓勵農戶重新養豬。

越南農業暨農村發展部數據顯示,非洲豬瘟疫情2月爆發以來,全國63省市、667縣、8532個村落淪陷,被迫撲殺染病豬隻約600萬頭,重量約34萬2000噸,占全國豬肉總重量的9%。由於豬肉供給減少,越南各地豬肉價格最近飆漲不斷,創下10年來新高,消費者肉品食用習慣受到影響。豬肉價格飆漲,造成越南12月消費者物價指數(CPI)較11月上漲1.4%,創下9年來新高。

「線上知識報」新聞網站26日報導,越南農業暨農村發展部部長阮春強(Nguyen Xuan Cuong)受訪表示,越南非洲豬瘟疫苗自主研發工作目前取得了初步進展,未來將與美國與荷蘭合作研製疫苗。

阮春強表示,美國農業專家明年1月將前來越南,共同合作研發與生產非洲豬瘟疫苗,「在不久的將來,與確保生物安全等措施的同時,我們正在為推動養殖業永續發展創造便利條件」。越南農業機構表示,目前非洲豬瘟疫情逐漸趨緩,因此鼓勵農戶在確保生物安全的情況下重新養豬,推動家禽與其他家畜等養殖業發展,同時加強宣導改變消費者以豬肉為主的肉品食用習慣。

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

【其他文章推薦】

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

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

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

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

擴大中國電動車佈局 鴻海今年據點數可能突破 10 個

鴻海集團擬擴大在大陸電動車租車佈局,繼成功搶佔北京、杭州、常州後,7 月即將前進貴陽。鴻海指出,去年北京成功試點後,已累積相當經驗,今年將加速複製,內部規畫今年據點數可望突破 10 個,相較去年僅有北京 1 個據點,年成長逾 10 倍。   鴻海進軍電動車市場動作頻頻,繼去年與大陸北汽集團合作,共同組成新能源汽車租賃公司北京恆譽,搶進分時租車市場後,歷經一年,目前北京恆譽共設有 200 個充電椿,並提供 1,000 多輛北汽「E150EV」電動車供租賃。   今年鴻海集團還將大刀闊斧展開擴點,光是上半年就已順利進駐杭州、常州,貴陽也預定 7 月進駐,屆時將成立黔譽的子公司負責管理。據了解,目前鴻海手中還有幾個新點在考慮中,包括上海、深圳、梧州,目標是今年底前總據點數突破 10 個的基本門檻。   法人指出,鴻海透過電動車租賃,提前卡位電動車市場,目標不單是電動車租賃市場,更重要的是後面的代工市場,將電動車市場大餅做大,最大獲益者還是鴻海集團。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

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

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

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

以色列電動車快速充電技術 僅需 5 分鐘充飽電

以色列初創公司 StoreDot 曾研發 30 秒快速手機充電技術,最近 StoreDot 將這項技術延伸至電動車電池上。StoreDot 研發的汽車版電池,只需 5 分鐘就能充滿,跟在油站入油分別不大。   專為電動車研發的 FlashBattery 電池可算是 StoreDot 手機電池的放大版,利用比傳統鋰離子科技更安全和穩定的有機化合物製作。FlashBattery 的最大好處是在極短時間充滿之餘,同時擁有較長的壽命。StoreDot 表示 FlashBattery 可以充電和放電過千次,比起鋰電池多三倍。   這款高效電池仍在研發中,在推出車用電池之前,StoreDot 會在今年年底前正式推出手機版,以電動車版電池原型預計要到明年底才會現身。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

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

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