当前位置: 首页 > news >正文

Docker实战02|Namespace

在上一文《Docker实战01|容器与开发语言》中主要介绍了Docker的基本概念与Docker安装、Go语言安装等实战技巧。

本文继续针对Namespace技术展开讲解并利用Go语言进行实践。

本系列所有代码均已经开源。关公众号回复「Go语言实现Docker」即可获得。

目录

  • 2.1.2 UTS Namespace
  • 2.1.3 IPC Namespace
  • 2.1.4 PID Namespace
  • 2.1.5 Mount Namespace
  • 2.1.6 User Namespace
  • 2.1.7 NetWork Namespace

第二章 基础技术

2.1 Linux Namespace 介绍

我们经常听到,Docker是一个使用了LinuxNamespace和Cgroups的虚拟化工具。但是,什么是LinuxNamespace,它在Docker内是怎么被使用的?说到这里,很多人就会迷茫。下面就先来介绍一下LinuxNamespace及它们是如何在容器中使用的。

2.1.1 概念

比如,一家公司向外界出售自己的计算资源。公司有一台性能还不错的服务器,每个用户买到一个tomcat实例用来运行它们自己的应用。有些调皮的客户可能不小心进入了别人的tomcat实例,修改或关闭了其中的某些资源,这样就会导致各个客户之间互相干扰。 也许你会说,我们可以限制不同用户的权限,让用户只能访问自己名下的tomcat实例,但是,有些操作可能需要系统级别的权限,比如root权限。我们不可能给每个用户都授予root权限,也不可能给每个用户都提供一台全新的物理主机让他们互相隔离。因此,LinuxNamespace在这里就派上了用场。**使用Namespace,就可以做到uid级别的隔离,也就是说,可以以uid为n的用户,虚拟化出来一个Namespace,在这个Namespace里面,用户是具有root权限的。但是,在真实 的物理机器上,他还是那个以uid为n的用户,这样就解决了用户之间隔离的问题。**当然这只是Namespace其中的一个简单功能。

除了UserNamespace,PID也是可以被虚拟的。命名空间建立系统的不同视图,从用户的角度来看,每一个命名空间应该像一台单独的Linux计算机一样,有自己的init进程(PID为I),其他进程的PID依次递增,A和B空间都有PID为1的init进程,子命名空间的进程映射到父命名空间的进程上,父命名空间可以知道每一个子命名空间的运行状态,而子命名空间与子命名空间之间是隔离的。PID映射关系图中可以看到,进程3在父命名空间中的PID为3,但是在子命名空间内,它的PID就是1。也就是说用户从子命名空间A内看进程3就像init进程一样,以为这个进程是自己的初始化进程,但是从整个host来看,它其实只是3号进程虚拟化出来的一个空间而己。


当前Linux一共实现了6种不同类型的Namespace。


Namespace的API主要使用如下3个系统调用 。

  • clone() 创建新进程。根据系统调用参数来判断哪些类型的Namespace被创建,而且它们的子进程也会被包含到这些Namespace中。
  • unshare() 将进程移出某个Namespace。
  • setns() 将进程加入到Namespace中。

2.1.2 UTS Namespace

UTS Namespace主要用来隔离nodename和domainname两个系统标识。在UTS Namespace里面,每个Namespace允许有自己的hostname。

下面将使用Go来做一个UTS Namespace的例子。其实对于Namespace这种系统调用,使用C语言来描述是最好的,但是本文的目的是去实现Docker,由于Docker就是使用Go开发的,所以就整体使用Go来讲解。先来看一下如下代码,非常简单。

package namespaceimport ("log""os""os/exec""syscall"
)func main() {cmd := exec.Command("sh")cmd.SysProcAttr = &syscall.SysProcAttr{Cloneflags: syscall.CLONE_NEWUTS,}cmd.Stdin = os.Stdincmd.Stdout = os.Stdoutcmd.Stderr = os.Stderrif err := cmd.Run(); err != nil {log.Fatalln(err)}
}

执行go run main.go

root@i:~/go/src/docker# go run main.go 
sh-5.1#

查看以下是否真的进入了新的 UTS Namespace。
执行pstree -pl
重点关注:

├─sh(2309337)───node(2309347)─┬─node(2309457)─┬─bash(2325085)───go(2328552)─┬─main(2328610)─┬─bash(2328614)───go(2329013)─┬─main(2329063)─┬─sh(2329067)───pstree(2329644)

main程序pid为2328610,后续新创建的sh pid为2329067,现在查看二者uts是否相同即可:

sh-5.1# readlink /proc/2328610/ns/uts
uts:[4026531838]
sh-5.1# readlink /proc/2329067/ns/uts
uts:[4026532362]

可以看到它们确实不在同一个UTS Namespace中。由于UTS Namespace对hostname做了隔离,所以在这个环境内修改hostname应该不影响外部主机,在这个sh环境内执行如下代码示例。

下面来做一下实验。

sh-5.1# hostname sh
sh-5.1# hostname
sh

新开一个宿主机窗口,执行hostname

root@i# hostname
iZ2zed7lj4oetgoal2c8v7Z

可以看到外部的 hostname 并没有被修改影响,由此可了解 UTS Namespace 的作用。

2.1.3 IPC Namespace

IPC Namespace 用来隔离 sys V IPC和 POSIX message queues。

每个 IPC Namespace 都有自己的 Sys V IPC 和 POSIX message queues。

微调一下程序,只是修改了 Cloneflags,新增了 CLONE_NEWIPC,表示同时创建 IPC Namespace。

// 注: 运行时需要 root 权限。
func main() {cmd.SysProcAttr = &syscall.SysProcAttr{// Cloneflags: syscall.CLONE_NEWUTS,Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWIPC,}

运行并且进行测试

# 先查看宿主机上的 ipc message queue
root@iZ2zed7Z:~# ipcs -q
------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages # 然后创建一个 
root@iZ2zed7Z:~# ipcmk -Q
Message queue id: 0
# 再次查看,发现有了
root@iZ2zed7Z:~# ipcs -q
------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages    
0x75c132a7 0          root       644        0            0   

运行程序进入新的 shell


可以发现,在新的 Namespace 中已经看不到宿主机上的 message queue 了。说明 IPC Namespace 创建成功,IPC 已经被隔离。

2.1.4 PID Namespace

PID Namespace是用来隔离进程ID的。

这样就可以理解,在docker container 里面,使用ps -ef经常会发现,在容器内,前台运行的那个进程PID是1,但是在容器外,使用ps -ef会发现同样的进程却有不同的PID,这就是PID Namespace做的事情。

调整程序,增加 PID flags。

cmd.SysProcAttr = &syscall.SysProcAttr{// Cloneflags: syscall.CLONE_NEWUTS,// Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWIPC,Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWIPC | syscall.CLONE_NEWPID,}

运行并测试:

root@iZ:~/go/src/docker# go run main.go
sh-5.1# pstree -pl
main(2332072)─┬─sh(2332076)───pstree(2332172)

可以看到mian 的pid为2332072,sh的pid为2332076。
在程序开的sh中执行echo $$

sh-5.1# echo $$
1

发现pid 是1,说明再新开的 PID Namespace 中只有一个 bash 这个进程,而且被伪装成了 1 号进程。

2.1.5 Mount Namespace

Mount Namespace用来隔离各个进程看到的挂载点视图。

在不同Namespace的进程中,看到的文件系统层次是不一样的。 在Mount Namespace中调用mount()和umount()仅仅只会影响当前Namespace内的文件系统,而对全局的文件系统是没有影响的。

需要注意的是,Mount Namespace 的 flag 是CLONE_NEWNS,直接是 NEWNS 而不是 NEWMOUNT,因为 Mount Namespace 是 Linux 中实现的第一个 Namespace,当时也没想到后续会有很多类型的 Namespace 加入。

再次修改代码,增加 Mount Namespace 的 flag。

	cmd.SysProcAttr = &syscall.SysProcAttr{// Cloneflags: syscall.CLONE_NEWUTS,// Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWIPC,// Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWIPC | syscall.CLONE_NEWPID,Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWIPC | syscall.CLONE_NEWPID | syscall.CLONE_NEWNS,}

运行并测试:

root@iZ2zed:~/go/src/docker# go run main.go
sh-5.1# ls /proc
1     120      15       1765  225      2309231  2318013  2330980  234   3      419  797  843  95          cpuinfo        iomem        locks         scsi           uptime
10    121      16       1766  2290557  2309337  2323926  2331826  235   30     420  8    844  951         crypto         ioports      mdstat        self           version
100   12477    1630162  1767  230      2309347  2324122  2332069  2359  303    421  80   845  96          devices        irq          meminfo       slabinfo       version_signature
1004  126      1655406  18    2309061  2309457  2325016  2332738  236   304    427  809  85   98          diskstats      kallsyms     misc          softirqs       vmallocinfo
101   13       1655423  1839  2309068  2309605  2325027  2332746  237   31     5    81   86   99          dma            kcore        modules       stat           vmstat
103   1319     1656492  19    2309090  2312349  2325085  2333183  24    32     6    812  87   acpi        driver         keys         mounts        swaps          zoneinfo
104   1399     1659802  2     2309111  2312407  2325297  2333225  240   33     603  82   88   bootconfig  dynamic_debug  key-users    mtrr          sys
105   14       166      20    2309157  2312634  2325563  2333229  25    34     765  820  90   buddyinfo   execdomains    kmsg         net           sysrq-trigger
1087  1449264  1756     21    2309158  2312635  2328552  2333289  253   4      767  83   919  bus         fb             kpagecgroup  pagetypeinfo  sysvipc
11    1449266  1762     22    2309159  2317057  2328610  2333330  26    40269  782  837  92   cgroups     filesystems    kpagecount   partitions    thread-self
117   1452065  1763     223   2309160  2317141  2328614  2333331  27    417    788  84   926  cmdline     fs             kpageflags   pressure      timer_list
12    149      1764     224   2309161  2317400  233      2333332  29    418    796  842  93   consoles    interrupts     loadavg      schedstat     tty

以看到,有一大堆文件,这是因为现在查看到的其实是宿主机上的 /proc 目录。

现在把 proc 目录挂载到当前 Namespace 中来:

sh-5.1# mount -t proc proc /proc
sh-5.1#  /proc
sh: /proc: Is a directory
sh-5.1# ls /proc
1           bus       crypto     dynamic_debug  interrupts  kcore        kpagecount  meminfo  net           scsi      swaps          timer_list         vmallocinfo
5           cgroups   devices    execdomains    iomem       keys         kpageflags  misc     pagetypeinfo  self      sys            tty                vmstat
acpi        cmdline   diskstats  fb             ioports     key-users    loadavg     modules  partitions    slabinfo  sysrq-trigger  uptime             zoneinfo
bootconfig  consoles  dma        filesystems    irq         kmsg         locks       mounts   pressure      softirqs  sysvipc        version
buddyinfo   cpuinfo   driver     fs             kallsyms    kpagecgroup  mdstat      mtrr     schedstat     stat      thread-self    version_signature

可以看到,少了一些文件,少的主要是数字命名的目录,因为当前 Namespace 下没有这些进程,自然就看不到对应的信息了。

此时就可以通过 ps 命令来查看了:


可以看到,在当前 Namespace 中 bash 为 1 号进程。

这就说明,当前 Mount Namespace 中的 mount 和外部是隔离的,mount 操作并没有影响到外部,Docker volume 也是利用了这个特性。

2.1.6 User Namespace

User Narespace 主要是隔离用户的用户组ID。

也就是说,一个进程的 UserID 和GroupID 在不同的 User Namespace 中可以是不同的。

比较常用的是,在宿主机上以一个非 root 用户运行创建一个 User Namespace, 然后在 User Namespace 里面却映射成 root 用户。这意味着,这个进程在 User Namespace 里面有 root 权限,但是在 User Namespace 外面却没有 root 的权限。

再次修改代码,增加 User Namespace 的 flag:

	cmd.SysProcAttr = &syscall.SysProcAttr{Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWIPC | syscall.CLONE_NEWPID | syscall.CLONE_NEWNS | syscall.CLONE_NEWUSER,}

运行并测试:

首先在宿主机上查看一个 user 和 group:


可以看到,此时是 root 用户。

运行程序,进入新的 sh 环境,可以看到,UID 是不同的,说明 User Namespace 生效了。

2.1.7 Network Namespace

Network Namespace 是用来隔离网络设备、IP 地址端口等网络栈的 Namespace。
Network Namespace 可以让每个容器拥有自己独立的(虛拟的)网络设备,而且容器内的应用可以绑定到自己的端口,每个 Namespace 内的端口都不会互相冲突。

在宿主机上搭建网桥后,就能很方便地实现容器之间的通信,而且不同容器上的应用可以使用相同的端口。

再次修改代码,增加 Network Namespace 的 flag:

	cmd.SysProcAttr = &syscall.SysProcAttr{Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWIPC | syscall.CLONE_NEWPID | syscall.CLONE_NEWNS | syscall.CLONE_NEWUSER | syscall.CLONE_NEWNET,}

运行并测试:

首先看一下宿主机上的网络设备:


有 lo、eth0 等10个设备。
然后运行程序:


可以发现,新的 Namespace 中只有1个设备了,说明 Network Namespace 生效了。

小结

  • Docker 使用 namespace 进行隔离。
  • Namespace 的本质:Linux Namespace 是 Linux 提供的一种内核级别环境隔离的方法,本质就是对全局系统资源的一种封装隔离。

未完待续。。。

下一篇将会继续介绍Docker中Cgroup的核心原理。
所有Docker实战内容合集:《Docker就应该这么学》

本文所有内容都是基于「动手写Docker」此书。关注公众号,后台回复“动手写Docker”即可领取。

同时,准备了一份云原生实战大礼包送给大家,关注公众号,后台回复“云原生资料”即可领取。

相关文章:

Docker实战02|Namespace

在上一文《Docker实战01|容器与开发语言》中主要介绍了Docker的基本概念与Docker安装、Go语言安装等实战技巧。 本文继续针对Namespace技术展开讲解并利用Go语言进行实践。 本系列所有代码均已经开源。关公众号回复「Go语言实现Docker」即可获得。 目录 2.1.2 U…...

01-03

利用模板类完成顺序表...

数据可视化与地理空间

写在开头 数据可视化是将数据以图形形式呈现,使其更易于理解和分析的过程。在地理空间分析中,数据可视化不仅能够展示地理位置信息,还能够有效地传达地理空间数据的模式、趋势和关联。本文将探讨数据可视化在地理空间分析中的作用,介绍Python中常用的数据可视化工具,并深…...

【elfboard linux开发板】4. 文件点灯与创建多进程

ps:提升效率的小tips: 灵活运用vim操作命令,gg快速跳转到文件开头,G跳转到结尾 多行操作 ctrl V shift i 插入修改内容 esc退出编辑 sudo vi /etc/vim/vimrc 在文件中添加如下内容省略重复工作: autocmd BufNewFile …...

黑马程序员SSM框架-Maven进阶

视频链接:Maven-01-分模块开发的意义_哔哩哔哩_bilibili 分模块开发与设计 分模块开发意义 分模块开发 依赖管理 依赖传递 依赖传递冲突问题 可以点击红框按钮查看依赖情况。 可选依赖和排除依赖 继承和聚合 聚合 聚合工程开发 继承 聚合和继承的区别 属性 属性…...

MFC综合实验二学习记录

文章目录 虚函数和纯虚函数的区别?MFC中什么是UPDATE_COMMAND_UI 消息如何查看控件对应的成员变量模态对话框的理解HGDIOBJ" 类型的值不能用于初始化 "CBrush *" 类型的实体错误MFC编程中CDC类型和HDC类型有什么区别?关于WIDING和ALTERNA…...

Python 中的运算符介绍(1)

算数运算符 常见的% 、//、/ 用法 赋值运算符 赋值运算:将等号右边赋值给等号左边 常见场景: 比较运算符 代码解析: 逻辑运算符 位运算符(了解) 三目运算符 身份证运算符 成员运算符...

达梦数据库查询各表数据量/以及达梦更新统计信息

1、达梦数据库查询各表数据量 达梦数据库与开源的MySQL不一样,MySQL查询各表数据量非常简单 而达梦数据库就有一些地方要注意,先用这句去查↓ SELECT table_name, num_rows FROM all_tables WHERE tablespace_name 表空间名; 如果结果如下图一样&…...

Java---- 静态内部类与非静态内部类的区别

在面试中回答的很不全,所以再此做一个总结。 1 static 静态修饰符 在程序中任何变量或者代码都是在编译时由系统自动分配内存来存储的。 static修饰表示静态的,在类加载时JVM会把它放到方法区,被本类以及本类中所有实例所公用。在编译后所分…...

STM32 基础知识(探索者开发板)--135讲 ADC转换

ADC定义: ADC即模拟数字转换器,英文详称 Analog-to-digital converter,可以将外部的模拟信号转换 ADC数模转换中一些常用函数: 1. HAL_ADC_Init 函数 HAL_StatusTypeDef HAL_ADC_Init(ADC_HandleTypeDef *hadc); 初始化ADC 形参&…...

Java经典框架之SpringBoot

SpringBoot Java 是第一大编程语言和开发平台。它有助于企业降低成本、缩短开发周期、推动创新以及改善应用服务。如今全球有数百万开发人员运行着超过 51 亿个 Java 虚拟机,Java 仍是企业和开发人员的首选开发平台。 课程内容的介绍 1. SpringBoot基础 2. Spring…...

LeetCode75| 二叉搜索树

目录 700 二叉搜索树中的搜索 迭代 递归 450 删除二叉搜索树中的节点 700 二叉搜索树中的搜索 注意二叉搜索树的性质即可 迭代 class Solution { public:TreeNode* searchBST(TreeNode* root, int val) {while(root ! NULL){if(root->val < val)root root->r…...

博物馆3d虚拟场景复原制作有助于传承和弘扬中华民族优秀传统文化

古建筑3D虚拟复原是一种利用现代科技手段对古代建筑进行数字化保护和展示的方法。它通过高精度的三维扫描技术&#xff0c;将古建筑的形态、结构、材料等信息转化为数字化数据&#xff0c;再通过计算机图形学技术将这些数据重建为虚拟的三维模型。这种技术在古建筑保护、研究、…...

二维码地址门牌系统:便捷报修服务引领社区新篇章

文章目录 前言一、二维码门牌系统介绍二、便捷报修服务三、多功能应用四、技术发展与应用前景 前言 科技的快速发展引领了社区生活的新变革&#xff0c;其中二维码门牌系统技术在社区管理方面带来了极大的便利和智能化服务。本文将深入了解这项创新技术及其优势。 一、二维码门…...

c++基础(对c的扩展)

文章目录 命令空间引用基本本质引用作为参数引用的使用场景 内联函数引出基本概念 函数补充默认参数函数重载c中函数重载定义条件函数重载的原理 命令空间 定义 namespace是单独的作用域 两者不会相互干涉 namespace 名字 { //变量 函数 等等 }eg namespace nameA {int num;v…...

RS485数据采集模块,如何一次采集多个modbus设备数据?

在工业数据采集中&#xff0c;RS485是一种常见的数据通信协议&#xff0c;而Modbus则是其上的常用设备协议。那么&#xff0c;如何用一个模块高效采集多个Modbus设备的数据呢&#xff1f;这就是我们今天要探讨的话题&#xff01; 什么是RS485数据采集模块&#xff1f; 首先&a…...

面试 Vue 框架八股文十问十答第一期

面试 Vue 框架八股文十问十答第一期 作者&#xff1a;程序员小白条&#xff0c;个人博客 相信看了本文后&#xff0c;对你的面试是有一定帮助的&#xff01;关注专栏后就能收到持续更新&#xff01; ⭐点赞⭐收藏⭐不迷路&#xff01;⭐ 1&#xff09;MVVM 的理解 MVVM (Mod…...

【积微成著】性能测试调优实战与探索(存储模型优化+调用链路分析)| 京东物流技术团队

一、前言 性能测试之于软件系统&#xff0c;是保障其业务承载能力及稳定性的关键措施。以软件系统的能力建设为主线&#xff0c;系统能力设计工作与性能测试工作&#xff0c;既有先后之顺序&#xff0c;亦有相互之影响。以上&#xff0c;在性能测试的场景决策&#xff0c;架构…...

建立分位制,用标准去量化优化效果 - 启动优化为例

Android开发的四年多时间中&#xff0c;逐渐将自己的工作重心从业务移动到小型项目的架构设计&#xff0c;在此过程中代码的书写有了更高的标准和要求&#xff0c;性能优化从此伴随着工作脚步&#xff0c; 为什么要进行性能优化呢&#xff1f; 页面访问时长从1s增加到3s&#…...

Modbus 通信协议 二

Modbus 常用缩写 通用Modbus帧结构 -应用数据单元&#xff08;ADU&#xff09; Modbus数据模型 Modbus ADU 和 PDU 的长度 Modbus PDU结构 串行链路上的 Modbus 帧结构 Modbus 地址规则 ASCLL 模式 和 RTU 模式的比较 RTU 模式 RTU 模式位序列 帧格式 帧的标识与鉴别 CRC 循环冗…...

关于系统设计的一些思考

0.前言 当我们站在系统设计的起点&#xff0c;面对一个新的需求&#xff0c;我们该如何开始呢&#xff1f;这是许多处于系统分析与设计领域的新手常常思考的问题。有些人可能会误以为&#xff0c;只要掌握了诸如面向对象、统一建模语言、设计模式、微服务、Serverless、Servic…...

Java 第19章 IO流 课堂练习+本章作业

文章目录 Buffered流拷贝二进制文件创建文件写入文本读取文本文件存读Properties文件 Buffered流拷贝二进制文件 package com.hspedu.chapter19.outputStream;import java.io.*;public class BufferedCopy02 {public static void main(String[] args) {String srcFilePath &q…...

一键制作电子样册,提升企业品牌形象

​电子样册作为一种新型的宣传方式&#xff0c;具有许多优势。首先&#xff0c;它打破了传统纸质宣传册的局限性&#xff0c;可以随时随地展示企业的产品和服务。其次&#xff0c;电子样册可以通过多媒体形式展示企业的品牌形象&#xff0c;包括图片、视频、文字等多种形式&…...

Linux 的引导与服务控制

一 开机启动过程 bios加电自检-->mbr-->grub-->加载内核文件-->启动进程 1 bios家电自检 检测硬件是否正常&#xff0c;然后根据bios中的启动项设置&#xff0c;去找内核文件 2 mbr 因为grup太大,第一个扇区存不下所有的grub程序&#xff0c;所以分为2部分指…...

多输入多输出 | MATLAB实现SSA-CNN麻雀算法优化卷积神经网络多输入多输出预测

多输入多输出 | MATLAB实现SSA-CNN麻雀算法优化卷积神经网络多输入多输出预测 目录 多输入多输出 | MATLAB实现SSA-CNN麻雀算法优化卷积神经网络多输入多输出预测预测效果基本介绍模型背景程序设计参考资料 预测效果 基本介绍 MATLAB实现SSA-CNN麻雀算法优化卷积神经网络多输入…...

高端电流检测方案

随着过去传统的“开环”系统被智能和高效率“闭环”设计所取代&#xff0c;准确的电流检测在多种应用中变得越来越重要。常见的电流检测方法&#xff0c;需要将检流电阻串联进被测电流通路&#xff0c;再用放大电路放大检流电阻上的压降。这个放大电路常被称之为电流检测放大器…...

IP地址、子网掩码与网络地址

一、IP地址 在 TCP/IP 体系中&#xff0c;IP 地址是一个最基本的概念。IP地址的作用&#xff1a;实现和网上的其他设备进行通信 IP地址的表示方法 互联网上的每台主机&#xff08;或路由器&#xff09;的每个接口都分配一个全世界唯一的IP地址。该IP地址由ICANN分配。 IP地址…...

python 深度学习 记录遇到的报错问题10

本篇继python 深度学习 解决遇到的报错问题9_module d2l.torch has no attribute train_ch3-CSDN博客 一、CUDA error: no kernel image is available for execution on the device CUDA kernel errors might be asynchronously reported at some other API call,so the stackt…...

linux下docker搭建Prometheus +SNMP Exporter +Grafana进行核心路由器交换机监控

一、安装 Docker 和 Docker Compose https://docs.docker.com/get-docker/ # 安装 Docker sudo apt-get update sudo apt-get install -y docker.io# 安装 Docker Compose sudo apt-get install -y docker-compose二、创建配置文件及测试平台是否正常 1、选个文件夹作为自建…...

Github 2023-12-31 开源项目日报 Top10

根据Github Trendings的统计&#xff0c;今日(2023-12-31统计)共有10个项目上榜。根据开发语言中项目的数量&#xff0c;汇总情况如下&#xff1a; 开发语言项目数量TypeScript项目3Swift项目1Java项目1HTML项目1Astro项目1Python项目1C项目1Dart项目1Jupyter Notebook项目1C项…...

只做正品的购物网站/品牌营销经典案例

安装nodejs环境这个直接搜索安装即可&#xff0c;安装完成之后&#xff0c;通过如下命令检测环境变量是否安装成功&#xff1a;λ node -v# 输出版本号v12.13.1正确输入版本号即可。安装cnpmcnpm是淘宝镜像&#xff0c;可以加快依赖的安装速度npm install cnpm -g --registryht…...

广州网站建设推荐/百度上如何发广告

最近工作中接到一个需求&#xff0c;需要对一个MQ消息队列进行性能测试&#xff0c;测试其消费能力&#xff0c;开发提供了一个dubbo服务来供我调用发送消息。 这篇博客&#xff0c;介绍下如何利用jmeter来测试dubbo接口&#xff0c;并进行性能测试。。。 一、Dubbo简介 dubbo是…...

win7用自己ip做网站/搜索百度下载安装

系列文章目录 &#x1f351; Python语言基础—注释的作用及分类 &#x1f351; Python语言基础—常用运算符总结 &#x1f351; Python语言基础—定义变量与数据类型 &#x1f351; Python语言基础—if判断和循环总结 &#x1f351; Python语言基础—理解面向对象 &#x1f351…...

wordpress博客文章导出/百度客服在线咨询人工服务

NEW关注Tech逆向思维视频号最新视频→【高效增长——向数字化要效益】7月20日消息&#xff0c;美国当地时间周二&#xff0c;谷歌在博客文章中宣布&#xff0c;该公司计划在公共环境中再次测试增强现实&#xff08;AR&#xff09;眼镜原型。有些原型将看起来像普通眼镜&#xf…...

美食网站建设策划书/企业网站排名优化方案

2018年谷歌推出了跨平台框架Flutter&#xff0c;一时间让各位技术开发者兴趣暴涨(因为做过混合开发的程序猿早就被js的性能低效&#xff0c;rn的js桥接麻烦&#xff0c;weex的社区小和坑多。。。等技术而感到焦头烂额)。随着高性能的跨平台框架Flutter正式版一发布&#xff0c;…...

柔造网站定制/网络营销推广价格

第17讲为有条件跳转。 有条件跳转的指令通常为 J[N]Flag 有符号数比较的判定为: 大于(G) 等于(E) 小于(L) 无符号数比较的判定为: 大于(A) 等于(E) 小于(B) X, Y 中存放为16位有符号数&#xff0c;将X&#xff0c;Y中较大的数放入AX MOV AX, X CMP AX, Y JGE SKIP MOV AX, Y SK…...