云原生基础 docker & harbor

Linux Namespace浅析

https://zhuanlan.zhihu.com/p/102364063

Namespace是将内核的全局资源做封装,使得每个Namespace都有一份独立的资源,因此不同的进程在各自的Namespace内对同一种资源的使用不会互相干扰。

Linux对Namespace的操作,主要是通过clone、setns和unshare这3个系统调用来完成的,clone创建新进程时,接收一个叫flags的参数,这些flag包括CLONE_NEWNS、CLONE_NEWIPC、CLONE_NEWUTS、CLONE_NEWNET(Mount namespace)、CLONE_NEWPIDCLONE_NEWUSER,用于创建新的namespace,这样clone创建出来新进程之后就属于新的namespace了,后续新进程创建的进程默认属于同一namespace。

如果想要给已存在进程设置新的namespace,可通过unshare函数(long unshare(unsigned long flags))完成设置,其入参flags表示新的namespace。当想要给已存在进程设置已存在的namespace,可通过setns函数(int setns(int fd, int nstype))来完成设置,每个进程在procfs目录下存储其相关的namespace信息,可找到已存在的namesapce,然后通过setns设置即可:

[root@centos ~]# ls -l /proc/10401/ns
总用量 0
lrwxrwxrwx 1 root root 0 1月  12 11:36 ipc -> ipc:[4026531839]
lrwxrwxrwx 1 root root 0 1月  12 11:36 mnt -> mnt:[4026531840]
lrwxrwxrwx 1 root root 0 1月  12 11:36 net -> net:[4026531956]
lrwxrwxrwx 1 root root 0 1月  12 11:36 pid -> pid:[4026531836]
lrwxrwxrwx 1 root root 0 1月  12 11:36 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 1月  12 11:36 uts -> uts:[4026531838]

上述每个虚拟文件对应该进程所处的namespace,如果其他进程想进入该namespace,open该虚拟文件获取到fd,然后传给setns函数的fd入参即可,注意虚拟文件type和nstype要对应上。

目前Linux内核总共支持以下6种Namespace,分别是IPC、Network、Mount、PID、UTS、User

  • IPC:隔离System V IPC和POSIX消息队列。
  • Network:隔离网络资源。
  • Mount:隔离文件系统挂载点。
  • PID:隔离进程ID。
  • UTS:隔离主机名和域名。
  • User:隔离用户ID和组ID。

IPC

IPC也就是进程间通信,Linux下有多种进程间通信,比如socket、共享内存、Posix消息队列和SystemV IPC等,这里的IPC namespace针对的是SystemV IPC和Posix消息队列,其会用标识符表示不同的消息队列,进程间通过找到标识符对应的消息队列来完成通信,IPC namespace做的事情就是相同的标识符在不同namespace上对应不同的消息队列,这样不同namespace的进程无法完成进程间通信。

Network

Network Namespace隔离网络资源,每个Network Namespace都有自己的网络设备、IP地址、路由表、/proc/net目录、端口号等。每个Network Namespace会有一个loopback设备(除此之外不会有任何其他网络设备)。因此用户需要在这里面做自己的网络配置。IP工具已经支持Network Namespace,可以通过它来为新的Network Namespace配置网络功能。

Mount

Mount namesapce用户隔离文件系统挂载点,每个进程能看到的文件系统都记录在/proc/$$/mounts里。在创建了一个新的Mount Namespace后,进程系统对文件系统挂载/卸载的动作就不会影响到其他Namespace。

PID

PID Namespace用于隔离进程PID号,这样一来,不同的Namespace里的进程PID号就可以是一样的了。当创建一个PID Namespace时,第一个进程的PID号是1,也就是init进程。init进程有一些特殊之处,例如init进程需要负责回收所有孤儿进程的资源。另外,发送给init进程的任何信号都会被屏蔽,即使发送的是SIGKILL信号,也就是说,在容器内无法“杀死”init进程。

UTS

UTS为Unix Timesharing System的简称,包含内存名称、版本、底层体系结构等信息,UTS Namespace用于对主机名和域名进行隔离,也就是uname系统调用使用的结构体structutsname里的nodename和domainname这两个字段,UTS这个名字也是由此而来的。为什么需要uts namespace呢,因为为主机名可以用来代替IP地址,比如局域网通过主机名访问机器。

User

User Namespace用来隔离用户资源,比如一个进程在Namespace里的用户和组ID与它在host里的ID可以不一样,这样可以做到,一个host的普通用户可以在该容器(user namespace)下拥有root权限,但是它的特权被限定在容器内。(容器内的这类root用户,实际上还是有很多特权操作不能执行,基本上如果这个特权操作会影响到其他容器或者host,就不会被允许)

Linux Cgroup浅析

https://zhuanlan.zhihu.com/p/102372680

cgroups是Linux下控制一个(或一组)进程的资源限制机制,全称是control groups,可以对cpu、内存等资源做精细化控制,比如目前很多的Docker在Linux下就是基于cgroups提供的资源限制机制来实现资源控制的;除此之外,开发者也可以指直接基于cgroups来进行进程资源控制,比如8核的机器上部署了一个web服务和一个计算服务,可以让web服务仅可使用其中6个核,把剩下的两个核留给计算服务。cgroups cpu限制除了可以限制使用多少/哪几个核心之外,还可以设置cpu占用比(注意占用比是各自都跑满情况下的使用比例,如果一个cgroup空闲而另一个繁忙,那么繁忙的cgroup是有可能占满整个cpu核心的)。

cgroups概念

从实现角度来看,cgroups实现了一个通用的进程分组框架,不同资源的具体管理工作由各cgroup子系统来实现,当需要多个限制策略比如同时针对cpu和内存进行限制,则同时关联多个cgroup子系统即可。

cgroups子系统

cgroups为每种资源定义了一个子系统,典型的子系统如下:

  • cpu 子系统,主要限制进程的 cpu 使用率。
  • cpuacct 子系统,可以统计 cgroups 中的进程的 cpu 使用报告。
  • cpuset 子系统,可以为 cgroups 中的进程分配单独的 cpu 节点或者内存节点。
  • memory 子系统,可以限制进程的 memory 使用量。
  • blkio 子系统,可以限制进程的块设备 io。
  • devices 子系统,可以控制进程能够访问某些设备。
  • net_cls 子系统,可以标记 cgroups 中进程的网络数据包,然后可以使用 tc 模块(traffic control)对数据包进行控制。
  • freezer 子系统,可以挂起或者恢复 cgroups 中的进程。
  • ns 子系统,可以使不同 cgroups 下面的进程使用不同的 namespace。

每个子系统都是定义了一套限制策略,它们需要与内核的其他模块配合来完成资源限制功能,比如对 cpu 资源的限制是通过进程调度模块根据 cpu 子系统的配置来完成的;对内存资源的限制则是内存模块根据 memory 子系统的配置来完成的,而对网络数据包的控制则需要 Traffic Control 子系统来配合完成。

Docker安装

yum安装

https://developer.aliyun.com/mirror/docker-ce

# step 1: 安装必要的一些系统工具
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
# Step 2: 添加软件源信息
sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# Step 3
sudo sed -i 's+download.docker.com+mirrors.aliyun.com/docker-ce+' /etc/yum.repos.d/docker-ce.repo
# Step 4: 更新并安装Docker-CE
sudo yum makecache fast
sudo yum -y install docker-ce
# Step 4: 开启Docker服务
sudo service docker start

# 注意:
# 官方软件源默认启用了最新的软件,您可以通过编辑软件源的方式获取各个版本的软件包。例如官方并没有将测试版本的软件源置为可用,您可以通过以下方式开启。同理可以开启各种测试版本等。
# vim /etc/yum.repos.d/docker-ce.repo
#   将[docker-ce-test]下方的enabled=0修改为enabled=1
#
# 安装指定版本的Docker-CE:
# Step 1: 查找Docker-CE的版本:
yum list docker-ce.x86_64 --showduplicates | sort -r
   Loading mirror speeds from cached hostfile
   Loaded plugins: branch, fastestmirror, langpacks
   docker-ce.x86_64            3:20.10.9-3.el7                     docker-ce-stable
   docker-ce.x86_64            3:20.10.8-3.el7                     docker-ce-stable
   docker-ce.x86_64            3:20.10.7-3.el7                     docker-ce-stable
   docker-ce.x86_64            3:20.10.6-3.el7                     docker-ce-stable
   docker-ce.x86_64            3:20.10.5-3.el7                     docker-ce-stable
   docker-ce.x86_64            3:20.10.4-3.el7                     docker-ce-stable
   docker-ce.x86_64            3:20.10.3-3.el7                     docker-ce-stable
   Available Packages
# Step2: 安装指定版本的Docker-CE: (VERSION例如上面的17.03.0.ce.1-1.el7.centos)
sudo yum -y install docker-ce.x86_64 3:20.10.12-3.el7


cat /etc/docker/daemon.json
{
  "insecure-registries": ["http://10.0.2.13"],
  "live-restore": true
}

docker 常用命令

https://docs.docker.com/engine/reference/commandline/docker/

# 显示 Docker 系统信息
docker info

# 拉取 centos:7 镜像
docker pull centos:7

# 根据当前目录的Dockerfile构建app:v1镜像
docker build -t app:v1 .

# 在容器 57a77a350082 里执行 ls /etc/blackbox_exporter/config.yml 命令
docker exec -it 57a77a350082 ls /etc/blackbox_exporter/config.yml

# 用镜像nginx:latest 启动容器
docker run --name nginx nginx:latest

# 将容器 57a77a350082 中的 /etc/blackbox_exporter/config.yml 文件复制到本地 /tmp 目录下
docker cp 57a77a350082:/etc/blackbox_exporter/config.yml /tmp

# 显示目前正在运行的容器
docker ps

# 显示当前阶段所有的容器
docker ps -a

# 停止容器 807a9a776ac6
docker stop 807a9a776ac6

# 显示容器f49fc00fe206的后100行日志
docker logs -n 100 f49fc00fe206

Harbor

单机部署

# docker安装参考上文
# 安装docker-compose
curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod u+x /usr/local/bin/docker-compose

# 下载Harbor离线安装包 
curl -O -L https://github.com/goharbor/harbor/releases/download/v2.4.1/harbor-offline-installer-v2.4.1.tgz
tar -xzf harbor-offline-installer-v2.4.1.tgz -C /opt/
cd /opt/harbor

# 配置 harbor.yml
harbor]# vi harbor.yml
# 修改主机名
hostname: 10.0.2.11
# 禁用https访问
# https:
#  # https port for harbor, default is 443
#  port: 443
#  # The path of cert and key files for nginx
#  certificate: /your/certificate/path
#  private_key: /your/private/key/path

# 创建数据目录
mkdir /data

# 安装选项
harbor]# ./install.sh --help

Note: Please set hostname and other necessary attributes in harbor.yml first. DO NOT use localhost or 127.0.0.1 for hostname, because Harbor needs to be accessed by external clients.
Please set --with-notary if needs enable Notary in Harbor, and set ui_url_protocol/ssl_cert/ssl_cert_key in harbor.yml bacause notary must run under https. 
Please set --with-trivy if needs enable Trivy in Harbor
Please set --with-chartmuseum if needs enable Chartmuseum in Harbor

# 执行安装
harbor]# ./install.sh --with-trivy
[Step 0]: checking if docker is installed ...
Note: docker version: 20.10.12
[Step 1]: checking docker-compose is installed ...
Note: docker-compose version: 1.29.2
[Step 2]: loading Harbor images ...
......
[Step 3]: preparing environment ...
......
[Step 4]: preparing harbor configs ...
......
[Step 5]: starting Harbor ...
Creating network "harbor_harbor" with the default driver
......
✔ ----Harbor has been installed and started successfully.----

HA部署

主机规划

IP 角色
10.0.2.11 harbor-db、redis 、haproxy
10.0.2.12 harbor
10.0.2.13 harbor

所有机器关闭防火墙、SELinux

systemctl stop firewalld && systemctl disable firewalld
setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config

配置外部数据库

# 和单机部署一样,解压安装包
tar -xzf harbor-offline-installer-v2.4.1.tgz -C /opt/
cd /opt/harbor

# 配置 harbor.yml,修改hostname,关闭https
harbor]# vi harbor.yml
hostname: 10.0.2.11
# https related config
#https:
#  # https port for harbor, default is 443
#  port: 443
#  # The path of cert and key files for nginx
#  certificate: /your/certificate/path
#  private_key: /your/private/key/path

# 执行 ./prepare 脚本,成功后会生成 docker-compose.yml 文件
harbor]#  ./prepare

# 修改 docker-compose.yml 文件,只保留 log,postgresql,redis 这3个service,postgresql映射5432端口,redis映射6379端口
harbor]# cat docker-compose.yml
version: '2.3'
services:
  log:
    image: goharbor/harbor-log:v2.4.1
    container_name: harbor-log
    restart: always
    cap_drop:
      - ALL
    cap_add:
      - CHOWN
      - DAC_OVERRIDE
      - SETGID
      - SETUID
    volumes:
      - /var/log/harbor/:/var/log/docker/:z
      - type: bind
        source: ./common/config/log/logrotate.conf
        target: /etc/logrotate.d/logrotate.conf
      - type: bind
        source: ./common/config/log/rsyslog_docker.conf
        target: /etc/rsyslog.d/rsyslog_docker.conf
    ports:
      - 127.0.0.1:1514:10514
    networks:
      - harbor
  postgresql:
    image: goharbor/harbor-db:v2.4.1
    container_name: harbor-db
    restart: always
    cap_drop:
      - ALL
    cap_add:
      - CHOWN
      - DAC_OVERRIDE
      - SETGID
      - SETUID
    volumes:
      - /data/database:/var/lib/postgresql/data:z
    ports:
      - 5432:5432
    networks:
      harbor:
    env_file:
      - ./common/config/db/env
    depends_on:
      - log
    logging:
      driver: "syslog"
      options:
        syslog-address: "tcp://localhost:1514"
        tag: "postgresql"
    shm_size: '1gb'
  redis:
    image: goharbor/redis-photon:v2.4.1
    container_name: redis
    restart: always
    cap_drop:
      - ALL
    cap_add:
      - CHOWN
      - SETGID
      - SETUID
    volumes:
      - /data/redis:/var/lib/redis
    ports:
      - 6379:6379
    networks:
      harbor:
    depends_on:
      - log
    logging:
      driver: "syslog"
      options:
        syslog-address: "tcp://localhost:1514"
        tag: "redis"
networks:
  harbor:
    external: false

# 启动数据库,默认会初始化 notaryserver,notarysigner,registry 这3个数据库
harbor]# docker-compose up -d
harbor]# less /var/log/harbor/postgresql.log
...
harbor-db     | /docker-entrypoint.sh: running /docker-entrypoint-initdb.d/initial-notaryserver.sql
harbor-db     | CREATE DATABASE
harbor-db     | /docker-entrypoint.sh: running /docker-entrypoint-initdb.d/initial-notarysigner.sql
harbor-db     | CREATE DATABASE
harbor-db     | /docker-entrypoint.sh: running /docker-entrypoint-initdb.d/initial-registry.sql
harbor-db     | CREATE DATABASE
harbor-db     | You are now connected to database "registry" as user "postgres".
...

harbor]# docker-compose ps
   Name                 Command                  State                        Ports                  
-----------------------------------------------------------------------------------------------------
harbor-db    /docker-entrypoint.sh 96 13      Up (healthy)   0.0.0.0:5432->5432/tcp,:::5432->5432/tcp
harbor-log   /bin/sh -c /usr/local/bin/ ...   Up (healthy)   127.0.0.1:1514->10514/tcp               
redis        redis-server /etc/redis.conf     Up (healthy)   0.0.0.0:6379->6379/tcp,:::6379->6379/tcp

配置 harbor 节点

harbor 节点 除了hostname配置为各自节点IP,其他配置保持一致

harbor]# vi harbor.yml
# 修改主机名
hostname: 10.0.2.12

# 关闭https访问
# https:
#  # https port for harbor, default is 443
#  port: 443
#  # The path of cert and key files for nginx
#  certificate: /your/certificate/path
#  private_key: /your/private/key/path

# 配置外部数据库
# Uncomment external_database if using external database.
external_database:
  harbor:
    host: 10.0.2.11
    port: 5432
    db_name: registry
    username: postgres
    password: root123
    ssl_mode: disable
  notary_signer:
    host: 10.0.2.11
    port: 5432
    db_name: notarysigner
    username: postgres
    password: root123
    ssl_mode: disable
  notary_server:
    host: 10.0.2.11
    port: 5432
    db_name: notaryserver
    username: postgres
    password: root123
    ssl_mode: disable

# Uncomment external_redis if using external Redis server
external_redis:
  host: 10.0.2.11:6379
  registry_db_index: 1
  jobservice_db_index: 2
  chartmuseum_db_index: 3
  trivy_db_index: 5
  idle_timeout_seconds: 30

# 执行安装
harbor]# ./install.sh --with-trivy

配置仓库复制

先配置 仓库管理

再配置 复制管理

图形界面操作,参考文档,不再一一演示

https://goharbor.io/docs/2.4.0/administration/configuring-replication/

配置Haproxy代理

~]# yum install haproxy -y
 
# 增加 harbor代理配置段
~]# vi /etc/haproxy/haproxy.cfg

# 启用统计页面
listen stats
    bind  *:9090
    stats enable
    stats uri     /admin?stats
    stats realm HAPorxy\ Stats\ Page
    stats auth admin:admin
    stats admin if TRUE
# harbor 代理
listen harbor
    bind *:80
    mode http
    balance source
    server node02 node02:80 check
    server node03 node03:80 check

harbor-db 备份与恢复

# 进入harbor-db容器
docker exec -it harbor-db bash
postgres [ / ]$ id
uid=999(postgres) gid=999(postgres) groups=999(postgres)
postgres [ / ]$ ls -l /var/lib/postgresql/data
total 4
drwx------. 19 postgres postgres 4096 Dec 28 07:13 pg13

# 执行 psql
postgres [ /tmp ]$ psql -U postgres
psql (13.5)
Type "help" for help.

postgres=# \l
                                   List of databases
     Name     |  Owner   | Encoding |   Collate   |    Ctype    |   Access privileges   
--------------+----------+----------+-------------+-------------+-----------------------
 notaryserver | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =Tc/postgres         +
              |          |          |             |             | postgres=CTc/postgres+
              |          |          |             |             | server=CTc/postgres
 notarysigner | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =Tc/postgres         +
              |          |          |             |             | postgres=CTc/postgres+
              |          |          |             |             | signer=CTc/postgres
 postgres     | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | 
 registry     | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | 
 template0    | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +
              |          |          |             |             | postgres=CTc/postgres
 template1    | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +
              |          |          |             |             | postgres=CTc/postgres
(6 rows)

postgres=# \c registry
You are now connected to database "registry" as user "postgres".
registry=# \d 
                         List of relations
 Schema |                Name                |   Type   |  Owner   
--------+------------------------------------+----------+----------
 public | access                             | table    | postgres
 public | access_access_id_seq               | sequence | postgres
 public | alembic_version                    | table    | postgres
 public | artifact                           | table    | postgres
 public | artifact_blob                      | table    | postgres
...
(90 rows)

registry=# select username from harbor_user;
 username  
-----------
 anonymous
 admin
 yangxy
(3 rows)

# 备份数据库
docker exec harbor-db /bin/sh -c  "pg_dumpall -U postgres -c" > /tmp/dumpall.sql
# 将备份的sql复制到容器内
docker cp /tmp/dumpall.sql harbor-db:/tmp

# 容器内执行(执行数据恢复时先停掉harbor)
postgres [ /tmp ]$ psql -f dumpall.sql -U postgres

你可能感兴趣的:(云原生基础 docker & harbor)