56星座屋
当前位置: 首页 星座百科

docker里面的pod定义(容器与Pod有什么区别和联系)

时间:2023-07-06 作者: 小编 阅读量: 1 栏目名: 星座百科

不过,虽然Docker可以将此命名空间用于其容器,但由于固有的限制,它默认情况下没有使用。Cgroup命名空间仅提供一个容器的cgroup层次结构的孤立视图。探索容器的cgroupsLinux命名空间可以让容器中的进程认为自己是在一个专用的机器上运行。但是,看不到别的进程并不意味着不会受到其他进程的影响。可以通过检查cgroup虚拟文件系统中的相应子树来查看给定进程的cgroups限制。

刚开始接触 Kubernetes 时,你学到的第一件事就是每个 Pod 都有一个唯一的 IP 和主机名,并且在同一个 Pod 中,容器可以通过 localhost 相互通信。所以,显而易见,一个 Pod 就像一个微型的服务器。

但是,过段时间,你会发现 Pod 中的每个容器都有一个隔离的文件系统,并且从一个容器内部,你看不到在同一 Pod 的其他容器中运行的进程。好吧!也许 Pod 不是一个微型的服务器,而只是一组具有共享网络堆栈的容器。

但随后你会了解到,Pod 中的容器可以通过共享内存进行通信!所以,在容器之间,网络命名空间不是唯一可以共享的东西……

基于最后的发现,所以,我决定深入了解:

  • Pod 是如何在底层实现的

  • Pod 和 Container 之间的实际区别是什么

  • 如何使用 Docker 创建 Pod

在此过程中,我希望它能帮助我巩固我的 Linux、Docker 和 Kubernetes 技能。

1、探索 Container

OCI 运行时规范并不将容器实现仅限于 Linux 容器,即使用 namespace 和 Cgroup 实现的容器。但是,除非另有明确说明,否则本文中的容器一词指的是这种相当传统的形式。

设置实验环境(playground)

在了解构成容器的 namespace 和 cgroups 之前,让我们快速设置一个实验环境:

$ cat > Vagrantfile <<EOF# -*- mode: ruby -*-# vi: set ft=ruby :Vagrant.configure("2") do |config| config.VM.box = "debian/buster64" config.vm.hostname = "docker-host" config.vm.define "docker-host" config.vagrant.plugins = ['vagrant-vbguest'] config.vm.provider "virtualbox" do |vb| vb.cpus = 2 vb.memory = "2048" end config.vm.provision "shell", inline: <<-SHELL apt-get update apt-get install -y curl vim SHELL config.vm.provision "docker"endEOF$ vagrant up$ vagrant ssh

最后让我们启动一个容器:

$ docker run --name foo --rm -d --memory='512MB' --cpus='0.5' nginx

探索容器的 namespace

首先我们来看一下,当容器启动后,哪些隔离原语(primitives)被创建了:

# Look up the container in the process tree.$ ps auxfUSER PID ... COMMAND...root 4707 /usr/bin/containerd-shim-runc-v2 -namespace moby -id cc9466b3e...root 4727 \_ nginx: master process nginx -g daemon off;systemd4781 \_ nginx: worker processsystemd4782 \_ nginx: worker process# Find the namespaces used by 4727 process.$ sudo lsns NS TYPE NPROCS PID USER COMMAND...4026532157 mnt 3 4727 root nginx: master process nginx -g daemon off;4026532158 uts 3 4727 root nginx: master process nginx -g daemon off;4026532159 ipc 3 4727 root nginx: master process nginx -g daemon off;4026532160 pid 3 4727 root nginx: master process nginx -g daemon off;4026532162 net 3 4727 root nginx: master process nginx -g daemon off;

我们可以看到用于隔离以上容器的命名空间是以下这些:

  • mnt(挂载):容器有一个隔离的挂载表。

  • uts(Unix 时间共享):容器拥有自己的 hostname 和 domain。

  • ipc(进程间通信):容器内的进程可以通过系统级 IPC 和同一容器内的其他进程进行通信。

  • pid(进程 ID):容器内的进程只能看到在同一容器内或拥有相同的 PID 命名空间的其他进程。

  • net(网络):容器拥有自己的网络堆栈。

注意,用户(user)命名空间没有被使用,OCI 运行时规范提及了对用户命名空间的支持。不过,虽然 Docker 可以将此命名空间用于其容器,但由于固有的限制,它默认情况下没有使用。因此,容器中的 root 用户很可能是主机系统中的 root 用户。谨防!

另一个没有出现在这里的命名空间是 cgroup。我花了一段时间才理解 cgroup 命名空间与 cgroups 机制(mechanism)的不同。Cgroup 命名空间仅提供一个容器的 cgroup 层次结构的孤立视图。同样,Docker 也支持将容器放入私有 cgroup 命名空间,但默认情况下没有这么做。

探索容器的 cgroups

Linux 命名空间可以让容器中的进程认为自己是在一个专用的机器上运行。但是,看不到别的进程并不意味着不会受到其他进程的影响。一些耗资源的进程可能会意外的过多消耗宿主机上面共享的资源。

这时候就需要 cgroups 的帮助!

可以通过检查 cgroup 虚拟文件系统中的相应子树来查看给定进程的 cgroups 限制。Cgroupfs 通常被挂在 /sys/fs/cgroup 目录,并且进程特定相关的部分可以在 /proc/

PID=$(docker inspect --format '{{.State.Pid}}' foo)# Check cgroupfs node for the container main process (4727).$ cat /proc/${PID}/cgroup11:freezer:/docker/cc9466b3eb67ca374c925794776aad2fd45a34343ab66097a44594b35183dba010:blkio:/docker/cc9466b3eb67ca374c925794776aad2fd45a34343ab66097a44594b35183dba09:rdma:/8:pids:/docker/cc9466b3eb67ca374c925794776aad2fd45a34343ab66097a44594b35183dba07:devices:/docker/cc9466b3eb67ca374c925794776aad2fd45a34343ab66097a44594b35183dba06:cpuset:/docker/cc9466b3eb67ca374c925794776aad2fd45a34343ab66097a44594b35183dba05:cpu,cpuacct:/docker/cc9466b3eb67ca374c925794776aad2fd45a34343ab66097a44594b35183dba04:memory:/docker/cc9466b3eb67ca374c925794776aad2fd45a34343ab66097a44594b35183dba03:net_cls,net_prio:/docker/cc9466b3eb67ca374c925794776aad2fd45a34343ab66097a44594b35183dba02:perf_event:/docker/cc9466b3eb67ca374c925794776aad2fd45a34343ab66097a44594b35183dba01:name=systemd:/docker/cc9466b3eb67ca374c925794776aad2fd45a34343ab66097a44594b35183dba00::/system.slice/containerd.service

似乎 Docker 使用 /docker/

ID=$(docker inspect --format '{{.Id}}' foo)# Check the memory limit.$ cat /sys/fs/cgroup/memory/docker/${ID}/memory.limit_in_bytes536870912 # Yay! It's the 512MB we Requested!# See the CPU limits.ls /sys/fs/cgroup/cpu/docker/${ID}

有趣的是在不明确设置任何资源限制的情况下启动容器都会配置一个 cgroup。实际中我没有检查过,但我的猜测是默认情况下,CPU 和 RAM 消耗不受限制,Cgroups 可能用来限制从容器内部对某些设备的访问。

这是我在调查后脑海中呈现的容器:

2、探索 Pod

现在,让我们来看看 Kubernetes Pod。与容器一样,Pod 的实现可以在不同的 CRI 运行时(runtime)之间变化。例如,当 Kata 容器被用来作为一个支持的运行时类时,某些 Pod 可以就是真实的虚拟机了!并且正如预期的那样,基于 VM 的 Pod 与传统 Linux 容器实现的 Pod 在实现和功能方面会有所不同。

为了保持容器和 Pod 之间公平比较,我们会在使用 ContainerD/Runc 运行时的 Kubernetes 集群上进行探索。这也是 Docker 在底层运行容器的机制。

设置实验环境(playground)

这次我们使用基于 VirtualBox driver 和 Containd 运行时的 minikube 来设置实验环境。要快速安装 minikube 和 kubectl,我们可以使用 Alex Ellis 编写的 arkade 工具:

# Install arkade $ curl -sLS https://get.arkade.dev | sh$ arkade get kubectl minikube$ minikube start --driver virtualbox --container-runtime containerd

实验的 Pod,可以按照下面的方式设置:

$ kubectl --context=minikube apply -f - <<EOFapiVersion: v1kind: Podmetadata: name: foospec: containers: - name: app image: docker.io/kennethreitz/httpbin ports: - containerPort: 80 resources: limits: memory: "256Mi" - name: sidecar image: curlimages/curl command: ["/bin/sleep", "3650d"] resources: limits: memory: "128Mi"EOF

探索 Pod 的容器

实际的 Pod 检查应在 Kubernetes 集群节点上进行:

$ minikube ssh

让我们看看那里 Pod 的进程:

$ ps auxfUSER PID ... COMMAND...root 4947 \_ containerd-shim -namespace k8s.io -workdir /mnt/sda1/var/lib/containerd/...root 4966 \_ /pauseroot 4981 \_ containerd-shim -namespace k8s.io -workdir /mnt/sda1/var/lib/containerd/...root 5001 \_ /usr/bin/python3 /usr/local/bin/gunicorn -b 0.0.0.0:80 httpbin:app -k geventroot 5016 \_ /usr/bin/python3 /usr/local/bin/gunicorn -b 0.0.0.0:80 httpbin:app -k geventroot 5018 \_ containerd-shim -namespace k8s.io -workdir /mnt/sda1/var/lib/containerd/...100 5035 \_ /bin/sleep 3650d

基于运行的时间,上述三个进程组很有可能是在 Pod 启动期间创建。这很有意思,因为在清单文件中,只有两个容器,httpbin 和 sleep。

可以使用名为 ctr 的 ContainerD 命令行来交叉检查上述的发现:

$ sudo ctr --namespace=k8s.io containers lsCONTAINER IMAGE RUNTIME...097d4fe8a7002 docker.io/curlimages/curl@sha256:1a220 io.containerd.runtime.v1.linux...dfb1cd29ab750 docker.io/kennethreitz/httpbin:latest io.containerd.runtime.v1.linux...f0e87a9330466 k8s.gcr.io/pause:3.1 io.containerd.runtime.v1.linux

的确是三个容器被创建了。同时,使用另一个和 CRI 运行时监控的命令行 crictl 检测发现,仅仅只有两个容器:

$ sudo crictl psCONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID097d4fe8a7002 bcb0c26a91c90 About an hour ago Running sidecar 0 f0e87a9330466dfb1cd29ab750 b138b9264903f About an hour ago Running app 0 f0e87a9330466

但是注意,上述的 POD ID 字段和 ctr 输出的 pause:3.1 容器 id 一致。好吧,看上去这个 Pod 是一个辅助容器。所以,它有什么用呢?

我还没有注意到在 OCI 运行时规范中有和 Pod 相对应的东西。因此,当我对 Kubernetes API 规范提供的信息不满意时,我通常直接进入 Kubernetes Container Runtime 接口(CRI)Protobuf 文件中查找相应的信息:

// kubelet expects any compatible container runtime// to implement the following gRPC methods:service RuntimeService { ... rpc RunPodSandbox(RunPodSandboxRequest) returns (RunPodSandboxResponse) {} rpc StopPodSandbox(StopPodSandboxRequest) returns (StopPodSandboxResponse) {} rpc RemovePodSandbox(RemovePodSandboxRequest) returns (RemovePodSandboxResponse) {} rpc PodSandboxStatus(PodSandboxStatusRequest) returns (PodSandboxStatusResponse) {} rpc ListPodSandbox(ListPodSandboxRequest) returns (ListPodSandboxResponse) {} rpc CreateContainer(CreateContainerRequest) returns (CreateContainerResponse) {} rpc StartContainer(StartContainerRequest) returns (StartContainerResponse) {} rpc StopContainer(StopContainerRequest) returns (StopContainerResponse) {} rpc RemoveContainer(RemoveContainerRequest) returns (RemoveContainerResponse) {} rpc ListContainers(ListContainersRequest) returns (ListContainersResponse) {} rpc ContainerStatus(ContainerStatusRequest) returns (ContainerStatusResponse) {} rpc UpdateContainerResources(UpdateContainerResourcesRequest) returns (UpdateContainerResourcesResponse) {} rpc ReopenContainerLog(ReopenContainerLogRequest) returns (ReopenContainerLogResponse) {} // ... }message CreateContainerRequest { // ID of the PodSandbox in which the container should be created. string pod_sandbox_id = 1; // Config of the container. ContainerConfig config = 2; // Config of the PodSandbox. This is the same config that was passed // to RunPodSandboxRequest to create the PodSandbox. It is passed again // here just for easy reference. The PodSandboxConfig is immutable and // remains the same throughout the lifetime of the pod. PodSandboxConfig sandbox_config = 3;}

所以,Pod 实际上就是由沙盒以及在沙盒中运行的容器组成的。沙盒管理 Pod 中所有容器的常用资源,pause 容器会在 RunPodSandbox 调用中被启动。简单的互联网搜索就发现了该容器仅仅是一个 idle 进程。

探索 Pod 的命名空间

下面就是集群节点上的命名空间:

$ sudo lsns NS TYPE NPROCS PID USER COMMAND4026532614 net 4 4966 root /pause4026532715 mnt 1 4966 root /pause4026532716 uts 4 4966 root /pause4026532717 ipc 4 4966 root /pause4026532718 pid 1 4966 root /pause4026532719 mnt 2 5001 root /usr/bin/python3 /usr/local/bin/gunicorn -b 0.0.0.0:80 httpbin:app -k gevent4026532720 pid 2 5001 root /usr/bin/python3 /usr/local/bin/gunicorn -b 0.0.0.0:80 httpbin:app -k gevent4026532721 mnt 1 5035 100 /bin/sleep 3650d4026532722 pid 1 5035 100 /bin/sleep 3650d

前面第一部分很像 Docker 容器,pause 容器有五个命名空间:net、mnt、uts、ipc 以及 pid。但是很明显,httpbin 和 sleep 容器仅仅有两个命名空间:mnt 和 pid。这是怎么回事?

事实证明,lsns 不是检查进程名称空间的最佳工具。相反,要检查某个进程使用的命名空间,可以参考 /proc/${pid}/ns 位置:

# httpbin containersudo ls -l /proc/5001/ns...lrwxrwxrwx 1 root root 0 Oct 24 14:05 ipc -> 'ipc:[4026532717]'lrwxrwxrwx 1 root root 0 Oct 24 14:05 mnt -> 'mnt:[4026532719]'lrwxrwxrwx 1 root root 0 Oct 24 14:05 net -> 'net:[4026532614]'lrwxrwxrwx 1 root root 0 Oct 24 14:05 pid -> 'pid:[4026532720]'lrwxrwxrwx 1 root root 0 Oct 24 14:05 uts -> 'uts:[4026532716]'# sleep containersudo ls -l /proc/5035/ns...lrwxrwxrwx 1 100 101 0 Oct 24 14:05 ipc -> 'ipc:[4026532717]'lrwxrwxrwx 1 100 101 0 Oct 24 14:05 mnt -> 'mnt:[4026532721]'lrwxrwxrwx 1 100 101 0 Oct 24 14:05 net -> 'net:[4026532614]'lrwxrwxrwx 1 100 101 0 Oct 24 14:05 pid -> 'pid:[4026532722]'lrwxrwxrwx 1 100 101 0 Oct 24 14:05 uts -> 'uts:[4026532716]'

虽然不太容易去注意到,但 httpbin 和 sleep 容器实际上重用了 pause 容器的 net、uts 和 ipc 命名空间!

我们可以用 crictl 交叉检测验证:

# Inspect httpbin container.$ sudo crictl inspect dfb1cd29ab750{ ... "namespaces": [ { "type": "pid" }, { "type": "ipc", "path": "/proc/4966/ns/ipc" }, { "type": "uts", "path": "/proc/4966/ns/uts" }, { "type": "mount" }, { "type": "network", "path": "/proc/4966/ns/net" } ], ...}# Inspect sleep container.$ sudo crictl inspect 097d4fe8a7002...

我认为上述发现完美的解释了同一个 Pod 中容器具有的能力:

  • 能够互相通信

    • 通过 localhost 和/或

    • 使用 IPC(共享内存,消息队列等)

  • 共享 domain 和 hostname

然而,在看过所有这些命名空间如何在容器之间自由重用之后,我开始怀疑默认边界可以被打破。实际上,在对 Pod API 规范的更深入阅读后发现,将 shareProcessNamespace 标志设置为 true 时,Pod 的容器将拥有四个通用命名空间,而不是默认的三个。但是有一个更令人震惊的发现——hostIPC、hostNetwork 和 hostPID 标志可以使容器使用相应主机的命名空间。

有趣的是,CRI API 规范似乎更加灵活。至少在语法上,它允许将 net、pid 和 ipc 命名空间限定为 CONTAINER、POD 或 NODE。因此,可以构建一个 Pod 使其容器无法通过 localhost 相互通信 。

探索 Pod 的 cgroups

Pod 的 cgroups 是什么样的?systemd-cgls 可以很好地可视化 cgroups 层次结构:

$ sudo systemd-cglsControl group /:-.slice├─kubepods│ ├─burstable│ │ ├─pod4a8d5c3e-3821-4727-9d20-965febbccfbb│ │ │ ├─f0e87a93304666766ab139d52f10ff2b8d4a1e6060fc18f74f28e2cb000da8b2│ │ │ │ └─4966 /pause│ │ │ ├─dfb1cd29ab750064ae89613cb28963353c3360c2df913995af582aebcc4e85d8│ │ │ │ ├─5001 /usr/bin/python3 /usr/local/bin/gunicorn -b 0.0.0.0:80 httpbin:app -k gevent│ │ │ │ └─5016 /usr/bin/python3 /usr/local/bin/gunicorn -b 0.0.0.0:80 httpbin:app -k gevent│ │ │ └─097d4fe8a7002d69d6c78899dcf6731d313ce8067ae3f736f252f387582e55ad│ │ │ └─5035 /bin/sleep 3650d...

所以,Pod 本身有一个父节点(Node),每个容器也可以单独调整。这符合我的预期,因为在 Pod 清单中,可以为 Pod 中的每个容器单独设置资源限制。

此刻,我脑海中的 Pod 看起来是这样的:

3、利用 Docker 实现 Pod

如果 Pod 的底层实现是一组具有共同 cgroup 父级的半融合(emi-fused)容器,是否可以使用 Docker 生产类似 Pod 的构造?

最近我尝试做了一些类似的事情来让多个容器监听同一个套接字,我知道 Docker 可以通过 docker run —network container:

因此,当你使用 docker exec

我们可以使用仅仅安装了 Docker 的机器作为实验环境。但是这里我会使用一个额外的包来简化使用 cgroups:

$ sudo apt-get install cgroup-tools

首先,让我们配置一个父 cgroup 条目。为了简洁起见,我将仅使用 CPU 和内存控制器:

sudo cgcreate -g cpu,memory:/pod-foo# Check if the corresponding folders were created:ls -l /sys/fs/cgroup/cpu/pod-foo/ls -l /sys/fs/cgroup/memory/pod-foo/

然后我们创建一个沙盒容器:

$ docker run -d --rm \ --name foo_sandbox \ --cgroup-parent /pod-foo \ --ipc 'shareable' \ alpine sleep infinity

最后,让我们启动重用沙盒容器命名空间的实际容器:

# app (httpbin)$ docker run -d --rm \ --name app \ --cgroup-parent /pod-foo \ --network container:foo_sandbox \ --ipc container:foo_sandbox \ kennethreitz/httpbin# sidecar (sleep)$ docker run -d --rm \ --name sidecar \ --cgroup-parent /pod-foo \ --network container:foo_sandbox \ --ipc container:foo_sandbox \ curlimages/curl sleep 365d

你注意到我省略了哪个命名空间吗?没错,我不能在容器之间共享 uts 命名空间。似乎目前在 docker run 命令中没法实现。嗯,是有点遗憾。但是除开 uts 命名空间之外,它是成功的!

cgroups 看上去很像 Kubernetes 创建的:

$ sudo systemd-cgls memoryController memory; Control group /:├─pod-foo│ ├─488d76cade5422b57ab59116f422d8483d435a8449ceda0c9a1888ea774acac7│ │ ├─27865 /usr/bin/python3 /usr/local/bin/gunicorn -b 0.0.0.0:80 httpbin:app -k gevent│ │ └─27880 /usr/bin/python3 /usr/local/bin/gunicorn -b 0.0.0.0:80 httpbin:app -k gevent│ ├─9166a87f9a96a954b10ec012104366da9f1f6680387ef423ee197c61d37f39d7│ │ └─27977 sleep 365d│ └─c7b0ec46b16b52c5e1c447b77d67d44d16d78f9a3f93eaeb3a86aa95e08e28b6│ └─27743 sleep infinity

全局命名空间列表看上去也很相似:

$ sudo lsns NS TYPE NPROCS PID USER COMMAND...4026532157 mnt 1 27743 root sleep infinity4026532158 uts 1 27743 root sleep infinity4026532159 ipc 4 27743 root sleep infinity4026532160 pid 1 27743 root sleep infinity4026532162 net 4 27743 root sleep infinity4026532218 mnt 2 27865 root /usr/bin/python3 /usr/local/bin/gunicorn -b 0.0.0.0:80 httpbin:app -k gevent4026532219 uts 2 27865 root /usr/bin/python3 /usr/local/bin/gunicorn -b 0.0.0.0:80 httpbin:app -k gevent4026532220 pid 2 27865 root /usr/bin/python3 /usr/local/bin/gunicorn -b 0.0.0.0:80 httpbin:app -k gevent4026532221 mnt 1 27977 _apt sleep 365d4026532222 uts 1 27977 _apt sleep 365d4026532223 pid 1 27977 _apt sleep 365d

httpbin 和 sidecar 容器看上去共享了 ipc 和 net 命名空间:

# app container$ sudo ls -l /proc/27865/nslrwxrwxrwx 1 root root 0 Oct 28 07:56 ipc -> 'ipc:[4026532159]'lrwxrwxrwx 1 root root 0 Oct 28 07:56 mnt -> 'mnt:[4026532218]'lrwxrwxrwx 1 root root 0 Oct 28 07:56 net -> 'net:[4026532162]'lrwxrwxrwx 1 root root 0 Oct 28 07:56 pid -> 'pid:[4026532220]'lrwxrwxrwx 1 root root 0 Oct 28 07:56 uts -> 'uts:[4026532219]'# sidecar container$ sudo ls -l /proc/27977/nslrwxrwxrwx 1 _apt systemd-journal 0 Oct 28 07:56 ipc -> 'ipc:[4026532159]'lrwxrwxrwx 1 _apt systemd-journal 0 Oct 28 07:56 mnt -> 'mnt:[4026532221]'lrwxrwxrwx 1 _apt systemd-journal 0 Oct 28 07:56 net -> 'net:[4026532162]'lrwxrwxrwx 1 _apt systemd-journal 0 Oct 28 07:56 pid -> 'pid:[4026532223]'lrwxrwxrwx 1 _apt systemd-journal 0 Oct 28 07:56 uts -> 'uts:[4026532222]'

4、总结

Container 和 Pod 是相似的。在底层,它们主要依赖 Linux 命名空间和 cgroup。但是,Pod 不仅仅是一组容器。Pod 是一个自给自足的高级构造。所有 Pod 的容器都运行在同一台机器(集群节点)上,它们的生命周期是同步的,并且通过削弱隔离性来简化容器间的通信。这使得 Pod 更接近于传统的 VM,带回了熟悉的部署模式,如 sidecar 或反向代理。

1、https://github.com/opencontainers/runtime-spec/issues/3452、https://github.com/opencontainers/runtime-spec/pull/388

    推荐阅读
  • 形成酸雨的主要气体是什么(形成酸雨的主要气体)

    以下内容大家不妨参考一二希望能帮到您!形成酸雨的主要气体是什么酸雨是指PH小于5.6的雨雪或其他形式的降水,形成的主要气体有二氧化硫、三氧化硫、硫化氢、二氧化氮。酸雨主要是人为的向大气中排放大量酸性物质所造成的。酸雨又分硝酸型酸雨和硫酸型酸雨。

  • 木棉花的花语是什么(木棉花的意义)

    接下来我们就一起去了解一下吧!珍惜眼前的幸福,珍惜身边的人给他们快乐与幸福。它的花期通常在3月或者4月份,在这一段时间盛开,而传说中四月的第十一天,是木棉花盛开的日子,所以4月11被定为木棉花的日子。

  • 炒凉皮不碎技巧(炒凉皮不碎有什么技巧)

    以下内容大家不妨参考一二希望能帮到您!炒凉皮不碎技巧炒凉皮不碎技巧:就是在做凉皮时不能炒太久,变软会失去筋度。胡萝卜切丝,蒜薹切段,葱切花,猪肉切丝,大蒜拍扁。成品凉皮一张张卷起切粗条,抖散备用。生抽,白糖,盐,鸡精,醋,胡椒粉调成汁备用。热锅倒适量食用油烧热加入大蒜,肉丝翻炒至金黄,加入胡萝卜丝和蒜薹炒熟,凉皮翻炒均匀后随即淋入调好的汁儿翻炒均匀。

  • 近几年灭绝的鱼(瞭望在长江源寻鱼)

    长江被誉为我国淡水渔业的摇篮、鱼类基因的宝库。据青海省渔业部门统计,长江流域青海段分布有土著鱼类21种。因此,严格意义上长江源的关键鱼类指的是裂腹鱼中的小头裸裂尻鱼。2019年,李伟带领团队参加长江源科考时,将小头裸裂尻鱼列为长江源鱼类研究的代表对象。2019年4月,科考小组五个人,两台车,开始了沿河寻觅之旅。“全球平均气温上升已是科学界的共识,位于青藏高原的长江源是全球气候变化的敏感区。”科考发现,江源地区

  • 鹧鸪在什么时候季节鸣叫(鹧鸪的孵化期有多长)

    鹧鸪在什么时候季节鸣叫鹧鸪一般会在繁殖季节鸣叫,繁殖期为3-6月,3-4月间开始求偶交配。求偶期间鸣叫更为频繁,常在山岩、树桩、灌木或乔木枝上鸣叫,尤以黎明和黄昏时更甚,往往是一鸟先鸣叫,其他雄鸟一起跟随,此起彼伏。鹧鸪的孵化期在21天左右,雏鸟出壳后不久即可跟随亲鸟活动。鹧鸪的繁殖期为每年的3-6月,3-4月间开始求偶交配,每窝产卵3-6枚,多时可达8枚,卵为椭圆形或梨形,颜色为淡皮黄色至黄褐色。

  • 秋天的诗词(这些都是关于秋天的诗句)

    迢迢新秋夕,亭亭月将圆《戊申岁六月中遇火》,今天小编就来说说关于秋天的诗词?《戊申岁六月中遇火》自古逢秋悲寂寥,我言秋日胜春朝。《秋词》是处红衰翠减,苒苒物华休。惟有长江水,无语东流。宋·柳永《八声甘州》落时西风时候,人共青山都瘦。《昭君怨》雨色秋来寒,风严清江爽。《酬裴侍御对雨感时见赠》秋声万户竹,寒色五陵松。唐·李颀《望秦川》秋色无远近,出门尽寒山。宋·苏轼《九日次韵王巩》

  • 广州有几种车牌(广州车牌你有吗)

    在广州的普通上班族,有房贷还想拥有一辆车,已经不容易了。但有车想让个广州牌,那更是难上加难,再加之限行,参与摇号,竞价的人是越来越多,那中标的机会更是渺茫了!截止日期是8日24时止。9月拟配置的中小客车增量指标共16313个,是这样分配的:1.以摇号方式向单位和个人配置节能车增量指标7285个,其中,单位指标100个,个人指标7185个。

  • qq注销账号有哪几个步骤(QQ将开注销帐号功能)

    1999年2月10日,一个名为OICQ、只有几百K的软件正式上线。当时,腾讯方面表示,这是QQ团队对帐号注销功能的灰度测试。网友截图出于安全考虑,也有网友表示支持有人说,QQ不推出注销服务有自己的考虑,这是为了防止用户QQ密码被他人知道后恶意注销,给用户带来无法挽回的损失。腾讯2018年第三季度财报显示,QQ智能终端月活跃账户同比增长6.9%至6.979亿。

  • 高跟鞋不合脚怎么办(穿高跟鞋不合脚怎么办)

    4、合理利用袜子,如果不喜欢垫各种鞋垫的朋友,可以穿一双船袜,再穿高跟鞋,那样既不影响穿着效果,也不影响美观,也是比较简单和实用的方法。

  • 年四旺名字打分104分 年四旺事迹

    文章目录:一、年四旺相关名字打分113二、年四旺相关名字评分115三、年四旺相关名字推荐四、年四旺相关名字大全五、其他人还看了一、年四旺相关名字打分113年灯石志明年橘纪红兵武尊道后书法孔多塞年贷款孙敬媛年立秋里蓝业珍冯景华年见朱诗词林于思冯桂年粤日林格孟昭毅年家薛邑马布鱼鲁初雪苏沫沫卜庆中年上年掌柜秦源达刘登龙严学锋国韵酒年线高成江裘梦年维泗红沙日年周王克斌王翔千毛淑红龙威信李万和年神范小慧王大