CI/CD之Docker容器DevOps知识汇总

容器与虚拟主机的区别

安装

Mac

下载并安装即可:https://download.docker.com/mac/stable/Docker.dmg

# 查看信息的一些命令
docker --version
docker version
docker info
# 还可安装Kitematic进行可视化的安装

Mac/Windows下安装虚机的小技巧:Vagrant-首先要安装VirtualBox,然后在Vagrant下载页面进行软件的下载

vagrant --help
vagrant version

# 快速创建虚拟机
mkdir -p vagrant/centos
cd vagrant/centos/
# 初始化Vagrantfile
vagrant init centos/7
# 安装
vagrant up
# 通过ssh进入
vagrant ssh
# 查看状态
vagrant status
# 停止服务
vagrant halt
# 删除
vagrant destroy

# 因网络问题,有时需要通过迅雷等软件先把文件下载下来,再进行本地安装
# 本地安装box,以Windows 10为例
vagrant box add Microsoft/EdgeOnWindows10 /path/to/virtualbox.box 
vagrant init Microsoft/EdgeOnWindows10
vagrant up

# 安装 scp 插件,然后可通过 vagrant scp 命令拷贝本地文件或目录到主机上
vagrant plugin install vagrant-scp

搜索相关操作系统的Vagrantfile:https://app.vagrantup.com/boxes/search,找到相应文件后创建一个名为Vagrantfile的文件或直接根据命令初始化,再使用vagrant up进行安装

以CentOS安装为例:

# 卸载旧版本
sudo yum remove docker docker-client docker-client-latest docker-common docker-latest \
docker-latest-logrotate docker-logrotate docker-selinux docker-engine-selinux docker-engine
# 安装requirements
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
# 添加repo
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# 安装docker
sudo yum install docker-ce -y
# 启动docker
sudo systemctl start docker
sudo systemctl enable docker
# 运行Hello World
sudo docker run hello-world

启动 Vagrant 自动安装 Docker,修改 Vagrantfile 末尾为

config.vm.provision "shell", inline: <<-SHELL
    sudo yum remove docker docker-common docker-selinux docker-engine
    sudo yum install -y yum-utils device-mapper-persistent-data lvm2
    sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
    sudo yum install -y docker-ce
    sudo systemctl start docker
  SHELL
end

# 其它
# 设置桥接网络
config.vm.network "public_network", :bridge => 'en0: Wi-Fi (AirPort)'
#设置私有 IP
config.vm.network "public_network", ip: "192.168.1.120"

Docker Machine

Windows 和 Mac 安装时会默认带有 Docker Machine, Linux 下安装参见:https://github.com/docker/machine/releases/

# 创建一个名为 demo 的虚机
docker-machine create demo
# 显示虚拟机列表
docker-machine ls
# SSH 连接 demo
docker-machine ssh demo
# 启动 demo
docker-machine start demo
# 关闭 demo
docker-machine stop demo
# 删除 demo
docker-machine rm demo
# 本地执行
docker-machine env demo
eval $(docker-machine env demo)
# unset
docker-machine env --unset
eval $(docker-machine env --unset)

# 通过添加 vagrant 用户到 docker 组,在执行 docker 命令时不再 需要添加 sudo
sudo gpasswd -a vagrant docker

https://github.com/AliyunContainerService/docker-machine-driver-aliyunecs
把文件重命名为:/usr/bin/docker-machine-driver-aliyunecs
# 验证安装是否成功
docker-machine create -d aliyunecs --help
# 使用 Docker Machine 在阿里云上创建 Host
docker-machine create -d aliyunecs --aliyunecs-io-optimized=optimized --aliyunecs-instance-type=ecs.c4.large --aliyunecs-access-key-id=xxx --aliyunecs-access-key-secret=xxx --aliyunecs-region=cn-hangzhou demo

此外还可通过 Docker Playground 来进行测试,但经测试国内速度较慢且经常会空间不足无法创建,以上方法中推荐 Vagrant,灵活性较 Docker Machine 更强。

Docker 命令

# Dockerfile
from hub.c.163.com/library/tomcat
MAINTAINER Alan alan@xxx.com
COPY demo.war /usr/local/tomcat/webapps
# Build,demo:latest 分别为名称和标签
docker build -t  demo:latest .
# 指定端口并运行 -d 后台运行 -p 指定端口
docker run -d -p 8888:8080  demo
# 交互式运行 Container
docker run -it centos
# 以 /bin/bash 进入镜像交互式环境
docker run -it <IMAGE ID> /bin/bash

docker pull hub.c.163.com/library/tomcat:latest
# 查看容器名等信息
docker ps
# 进入容器
docker exec -it 12e1b6c023e bash
# 拷贝到本地
docker cp <container id>:/demo.war ./
docker inspect <container id>

# 安装 Wordpress(docker-compose.yml)
docker-compose build
docker-compose up

# 停止当前所有运行的 Docker
docker stop $(docker ps -a -q)
# 查看镜像
docker images
docker image ls
# 删除镜像,-f 为强制删除
docker rmi -f <image id>
#查看容器
docker container ls # 运行中的容器
docker container ls -a # 列出所有容器,与 docker ps -a相同
# 删除容器
docker container rm <container id>
# 列出所有容器 id,与docker container ls -a | awk {'print $1'}相似
docker container ls -aq 
# 删除所有容器
docker rm $(docker container ls -aq) # 或docker rm $(docker ps -aq)
# 删除已退出容器
docker rm $(docker container ls -f "status=exited" -q)
#容器运行日志
docker logs <CONTAINER ID>

Docker的镜像和容器

Docker Engine

  • 后台进程(dockerd)
  • REST API Server
  • CLI接口(docker)
Docker Engine

底层技术支持

  • Namespaces:做隔离 pid, net, ipc, mnt, uts
  • Control groups:做资源限制
  • Union file systems:Container 和 image 的分层
Docker Architecture

Docker 镜像

# 1、手写 Dockerfile 自行 build
FROM ubuntu:14.04
LABEL maintainer="Alan Hou <xxx@gmail.com>"
RUN apt-get update && apt-get install -y redis-server
EXPOSE 6379
ENTRYPOINT ["/usr/bin/redis-server"]
# build
docker build -t  ubuntu-14:latest .

# 2、docker pull
sudo docker pull ubuntu:14.04

# sudo docker images 进行查看

什么是 Image?

  • 文件和 meta data 的集合(root filesystem)
  • 分层的,并且每一层都可以添加改变删除文件,成为一个新的 image
  • 不同的 image 可以共享相同的 layer
  • Image 本身是 read-only 的
Docker 镜像
# 执行 hello-world
docker pull hello-world
docker run hello-world

# 手写 base image hello-world
mkdir hello-world
cd hello-world/
vi hello.c
#include<stdio.h>
int main()
{
        printf("hello docker!\n");
}

sudo yum install gcc glibc glibc-static -y
gcc -static hello.c -o hello
# 创建 Dockerfile
vi Dockerfile
FROM scratch
ADD hello /
CMD ["/hello"]

# build 我们的 base image
docker build -t alanhou/hello-world .
# 此时执行docker image ls就可以看到alanhou/hello-world
# 运行
docker run alanhou/hello-world

什么是 Container?

  • 通过 Image 创建(copy)
  • 在 Image layer 之上建立一个 container layer(可读写)
  • 类比面向对象:类(Image)和实例(Container)
  • Image负责 app 的存储和分发,Container 负责运行 app
# container commit 为 image
docker container commit/docker commit

# 示例:(把拉下来的 CentOS  进行修改后生成 Image,不推荐)
docker commit musing_aryabhata alanhou/centos-alan

docker image build/docker build

# 示例
vi Dockerfile
FROM centos
RUN yum install -y vim

docker build -t alanhou/centos-vim .

Dockerfile

FROM 指定 base image
FROM scratch # 从0开始
# 选择其它 base image
FROM centos  
FROM ubuntu:14.04

LABEL 指定 Metadata
LABEL maintainer="xxx@gmail.com"
LABEL version="1.0"
LABEL description="Demo description"

RUN执行命令
RUN yum update && yum install -y vim python-dev
RUN apt-get update && apt-get install -y perl \
pwgen --no-install-recommends && rm -rf \
/var/lib/apt/lists/*
RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME'

WORKDIR 设定当前工作目录
WORKDIR /test # 如果没有会自动创建
WORKDIR demo
RUN pwd

ADD and COPY把本地文件添加到 image 中
ADD hello /
ADD test.tar.gz / # 添加到根目录并解压
WORKDIR /root
ADD hello test/ # /root/test/hello
WORKDIR /root
COPY hello test/

ENV
ENV MYSQL_VERSION 5.6 # 设置常量
RUN apt-get install -y mysql-server= "${MYSQL_VERSION}" \ #引用常量
&& rm -rf /var/lib/apt/lists/*

VOLUMN and EXPOSE 存储和网络
CMD and ENTRYPOINT
# RUN:执行命令并创建新的 Image Layer
# CMD:设置容器启动后默认执行的命令和参数;如果 docker run 指定了其它命令,CMD命令被忽略;如果定义了多个 CMD,只有最后一个会执行
# ENTRYPOINT:设置容器启动时运行的命令;不会被忽略,一定会执行;最佳实践:写一个 shell 脚本作为 entrypoint

# Shell 格式
RUN apt-get install -y vim
CMD echo "hello docker"
ENTRYPOINT echo "hello docker"

# Exec 格式
RUN ["apt-get", "install", "-y", "vim"]
CMD ["/bin/echo", "hello docker"]
ENTRYPOINT ["/bin/echo", "hello docker"]

Docker 官方 Image 文件:https://github.com/docker-library
Docker 官方文档:https://docs.docker.com/engine/reference/builder/

Docker镜像的发布

https://hub.docker.com

首先注册用户

方法一:进入服务器执行

docker login
docker image push/docker push <REPOSITORY> # 如extratime/hello-world

方法二(推荐)Create Automated Build,关联 GitHub,会自动根据 Dockerfile 自动生成镜像

通过registry 搭建自己的私有 Docker Registry

sudo docker run -d -p 5000:5000 --restart always --name registry registry:2

默认 push 私有服务器不被信任(Get https://192.168.1.6:5000/v2/: http: server gave HTTP response to HTTPS client)

docker build -t xxx.xxx.xxx.xxx:5000/hello-world .

vi /etc/docker/daemon.json
{"insecure-registries":["xxx.xxx.xxx.xxx:5000"]}

vi /lib/systemd/system/docker.service
EnvironmentFile = /etc/docker/daemon.json
sudo systemctl daemon-reload
sudo systemctl reload docker

docker push xxx.xxx.xxx.xxx:5000/hello-world

Docker Registry Api 可用于查看验证 push 是否成功,如通过 http://your.ip.address:5000/v2/_catalog查看仓库,得到如下结果:

{
    repositories: [
        "hello-world"
    ]
}

示例文件(制作基于 Flask Hello World 程序的镜像)

# Dockerfile
FROM python:2.7
LABEL maintainer="Alan Hou<xxx@gmail.com>"
RUN pip install flask
COPY app.py /app/
WORKDIR /app
EXPOSE 5000
CMD ["python", "app.py"]

docker build -t alanhou/flask-hello-world .
# 对于中间状态的镜像可以通过/bin/bash 查看环境中存在的问题
docker run -it bacce0142ae /bin/bash
# 运行
docker run -d alanhou/flask-hello-world
# 进入运行中的容器
docker exec -it <CONTAINER ID> /bin/bash

示例文件2(带参数执行的 Docker Image)

# Dockerfile
FROM ubuntu
RUN apt-get update && apt-get install -y stress
ENTRYPOINT ["/usr/bin/stress"]
CMD []

# 创建镜像
docker build -t alanhou/ubuntu-stress .
# 运行
docker run -it alanhou/ubuntu-stress --vm 1

Docker的网络

网络是基于数据包的通信方式,网络的分层

网络的分层

Ping(ICMP协议)用于验证 IP 的可达性(防火墙可能会禁止 Ping 操作);telnet 用于检查服务的可用性(telnet ip.addr port)

Network Namespace 的小测试

# 添加网络命名空间
sudo ip netns add test1
sudo ip netns add test2
# 查看
sudo ip netns list
# 设置关联
sudo ip link add veth-test1 type veth peer name veth-test2
sudo ip link set veth-test1 netns test1
sudo ip link set veth-test2 netns test2
# 设置 IP
sudo ip netns exec test1 ip addr add 192.168.1.1/24 dev veth-test1
sudo ip netns exec test2 ip addr add 192.168.1.2/24 dev veth-test2
# 启动
sudo ip netns exec test1 ip link set dev veth-test1 up
sudo ip netns exec test2 ip link set dev veth-test2 up
# 查看IP 地址
sudo ip netns exec test1 ip a
sudo ip netns exec test2 ip a
# Ping 测试
sudo ip netns exec test2 ping 192.168.1.1

Docker 默认网络Bridge

# 启动容器 test1
docker run -d --name test1 busybox /bin/sh -c "while true; do sleep 3600; done"
# 查看网络并显示NETWORK ID
docker network ls
docker network inspect <NETWORK ID>
# 安装并查看桥接网络
sudo yum install -y bridge-utils
brctl show
# 启动容器 test2
docker run -d --name test2 busybox /bin/sh -c "while true; do sleep 3600; done"
docker network inspect bridge

# Docker Link
docker stop test2
docker rm test2
# 重新启动 test2
docker run -d --name test2 --link test1 busybox /bin/sh -c "while true; do sleep 3600; done"
docker exec -it test2 /bin/sh
# 在交互命令中除 ip 外还可通过 ping test1来测试连接
# 创建网络(通过-d 指定 driver)
docker network create -d bridge my-bridge
# 创建容器并指定网络
docker run -d --name test3 --network my-bridge busybox /bin/sh -c "while true; do sleep 3600; done"
# 连接已有容器到指定网络
docker network connect my-bridge test2
# 注:连接到自定网络中的容器默认相互 link,所以在 test2中通过 ping test3是可以连接的

# 端口映射 -p  为Port Map
docker run --name web -d -p 80:80 nginx

容器网络 none & host

docker run -d --name test1 --network none busybox /bin/sh -c "while true; do sleep 3600; done"
# 查看 none网络
docker network inspect none
# 进入容器,通过 ip a 命令会发现仅存在本地回环地址 lo,即局域网内无法访问
docker exec -it test1 /bin/sh
# 删除
docker stop test1 && docker rm test1

# 创建并设置 test1网络为 host
docker run -d --name test1 --network host busybox /bin/sh -c "while true; do sleep 3600; done"
# 查看 host网络
docker network inspect host
# 进入容器,通过 ip a可发现与宿主机相同,所以若启动多个服务(如 Nginx)可能会出现端口冲突的问题
docker exec -it test /bin/sh

更复杂的 Docker 测试

sudo docker run -d --name redis redis
docker build -t alanhou/flask-redis .
# -e 设置环境变量
docker run -d -p 5000:5000 --link redis --name flask-redis -e REDIS_HOST=redis alanhou/flask-redis

# app.py
from flask import Flask
from redis import Redis
import os
import socket

app = Flask(__name__)
redis = Redis(host=os.environ.get('REDIS_HOST', '127.0.0.1'), port=6379)

@app.route('/')
def hello():
    redis.incr('hits')
    return 'Hello Container World! I have been seen %s times and my hostname is %s.\n' % (redis.get('hits'),socket.gethostname())

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000, debug=True)

# Dockerfile
FROM python:2.7
LABEL maintaner="Alan Hou xxx@gmail.com"
COPY . /app/
WORKDIR /app
RUN pip install flask redis
EXPOSE 5000
CMD [ "python", "app.py" ]

Overlay 网络和多机容器间通信

# 在两台宿主机上分别执行
# 配置 etcd(分布式的 key,value 工具,用于管理并防止 IP 冲突)
wget https://github.com/coreos/etcd/releases/download/v3.0.12/etcd-v3.0.12-linux-amd64.tar.gz
tar zxvf etcd-v3.0.12-linux-amd64.tar.gz
cd etcd-v3.0.12-linux-amd64
# your.ip.addr为本机 IP,dest.ip.addr为需连接的服务器 IP, docker-node1,2可根据实际情况修改为其它名称
nohup ./etcd --name docker-node1 --initial-advertise-peer-urls http://your.ip.addr:2380 \
--listen-peer-urls http://your.ip.addr:2380 \
--listen-client-urls http://your.ip.addr:2379,http://127.0.0.1:2379 \
--advertise-client-urls http://your.ip.addr:2379 \
--initial-cluster-token etcd-cluster \
--initial-cluster docker-node1=http://your.ip.addr:2380,docker-node2=http://dest.ip.addr:2380 \
--initial-cluster-state new&
# 查看 etcd 服务状况
./etcdctl cluster-health
# 重新启动 docker 服务
sudo service docker stop
sudo /usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --cluster-store=etcd://your.ip.add:2379 --cluster-advertise=your.ip.addr:2375&

# 创建 overlay 网络(另一台机器会自动创建 docker network ls)
sudo docker network create -d overlay demo

# 在 A 主机上创建
docker run -d --name test1 busybox /bin/sh -c "while true; do sleep 3600; done" 
# 在 B 主机上创建
docker run -d --name test2 busybox /bin/sh -c "while true; do sleep 3600; done" 

# 此时会发现两个窗口之间可相互 ping 通,即实现了通信,如 docker exec -it test1 ping test2

Docker的持久化存储和数据共享

Docker 持久化数据的方案

  • 基于本地文件系统的 Volume:Data Volume,docker create 或 docker run 时添加-v 参数
  • 基于 plugin 的 Volume:第三方存储方案,如 NAS, AWS

以下为本地文件系统持久化的两种操作方法:

Data Volume

可通过 Dockerfile中的 VOLUME进行指定,如 MySQL的官方 Dockerfile 中使用VOLUME /var/lib/mysql

sudo docker run -d --name mysql1 -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql
sudo docker volume ls
sudo docker volume inspect <VOLUME NAME>
# 可以看到/var/lib/docker/volumes/下有存储相关目录,即使删除容器也不影响,如需删除volume,需手动执行
sudo docker volume rm <VOLUME NAME>
# 默认生成的<VOLUME NAME>太长,可以通过-v 参数指定,如:
sudo docker run -d -v mysql:/var/lib/mysql --name mysql1 -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql
# 会发现在我们删除容器后,重新使用相同的-v 参数原容器创建的数据库等信息依然存在

Bind Mounting

本地文件和容器之前的一个映射关系(/home/aaa 为本地,可使用$(pwd)映射本地目录)

docker run -v /home/aaa:/root/aaa

Docker Compose多容器部署

安装部署 Wordpress

# 安装 MySQL容器
docker run -d --name mysql -v mysql-data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=wordpress mysql:5.7
# 安装 Wordpress容器
docker run -d -e WORDPRESS_DB_HOST=mysql:3306 --link mysql -p 80:80 wordpress

Docker Compose是一个可以通过一个 yml 文件定义多容器 Docker应用的工具,默认名称 docker-compose.yml
services:一个 service 代表一个 container,启动类似 docker run

Windows, Mac 默认已安装 Docker Compose,Linux

sudo curl -L "https://github.com/docker/compose/releases/download/1.23.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
# 查看安装状况
docker-compose --version

以上述 Wordpress 部署为例

docker-compose.yml

version: '3'

services:

  wordpress:
    image: wordpress
    ports:
      - 80:80
    environment:
      WORDPRESS_DB_HOST: mysql
      WORDPRESS_DB_PASSWORD: root
    networks:
      - my-bridge

  mysql:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: wordpress
    volumes:
      - mysql-data:/var/lib/mysql
    networks:
      - my-bridge

volumes:
  mysql-data:

networks:
  my-bridge:
    driver: bridge

执行

docker-compose up -d
# 或指定 yml 文件
docker-compose -f docker-compose.yml up -d

其它命令

# 停止服务
docker-compose stop
# 停止并删除
docker-compose down
# 查看
docker-compose ps
docker-compose images
docker-compose exec ...

水平扩展和负载均衡

# 修改前述docker-compose.yml 文件:删除 wordpress 下的 ports 部分,并在 services 下添加
lb:
    image: dockercloud/haproxy
    links:
      - wordpress
    ports:
      - 80:80
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
# 执行如下命令即可实现负载均衡,数字3可修改为其它想要启动的容器数
docker-compose up --scale wordpress=3 -d

容器编排Docker Swarm

容器编排 Docker Swarm
# 在 Swarm Manager上运行
docker swarm init --advertise-addr=your.ip.add
# 运行结束时会提示,在 Swarm Work 上运行该命令即可
docker swarm join --token <Swarm Manager Token> your.manager.ip.addr:2377
# 执行完成后可在 Swarm Manager 上查看节点
docker node ls

# 在 Swarm Manager 上创建Service
docker service create --name demo busybox sh -c "while true; do sleep 3600; done"
# 查看 service
docker service ls
# 查看指定 service所在节点等信息
docker service ps demo
# 水平扩展
docker service scale demo=3
# 删除
docker service rm demo

基于上述Docker Swarm 集群部署 Wordpress

# 创建 Overlay 网络(manager)
docker network create -d overlay demo
# 安装 MySQL
docker service create --name mysql --env MYSQL_ROOT_PASSWORD=root --env MYSQL_DATABASE=wordpress --network demo --mount type=volume,source=mysal-data,destination=/var/lib/mysql mysql:5.7
# 安装 Wordpress
docker service create --name wordpress -p 80:80 --env WORDPRESS_DB_PASSWORD=root --env WORDPRESS_DB_HOST=mysql --network demo wordpress

此时便完成了 Wordpress 的部署,我们会发现通过所有节点的 IP 均可访问该站点

集群服务器间通信 Routing Mesh测试

docker service create --name whoami -p 8000:8000 --network demo -d jwilder/whoami
docker service create --name client -d --network demo busybox sh -c "while true; do sleep 3600; done"

Routing Mesh两种体现

  • Internal-容器之间的访问通过 Overlay 网络(通过 VIP 虚拟 IP)
  • Ingress-如果服务有绑定接口,则此服务可以通过任意 Swarm 节点的相应接口访问
    • 外部访问的负载均衡
    • 服务端口被暴露到各个 Swarm 节点
    • 内部通过 IPVS 进行负载均衡

Ingress 查看相关命令

sudo yum install -y ipvsadm
sudo nsenter --net=/var/run/docker/netns/ingress_sbox
# 进入 ingress_box 后查看虚拟 IP 指向
sudo iptables -nL -t mangle
# 查看具体 IP
ipvsadm -l
Ingress Network 数据走向

Docker Stack部署 Wordpress

docker stack deploy web --compose-file=docker-compose.yml

# docker-compose.yml 修改网络为 overlay,MySQL 仅允许在 Manager 节点上
version: '3'
services:
  wordpress:
    image: wordpress
    ports:
      - 80:80
    environment:
      WORDPRESS_DB_HOST: mysql
      WORDPRESS_DB_PASSWORD: root
    networks:
      - my-network
    depends_on:
      - mysql
    deploy:
      mode: replicated
      replicas: 3
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
      update_config:
        parallelism: 1
        delay: 10s

  mysql:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: wordpress
    volumes:
      - mysql-data:/var/lib/mysql
    networks:
      - my-network
    deploy:
      mode: global
      placement:
        constraints:
          - node.role == manager

volumes:
  mysql-data:

networks:
  my-network:
    driver: overlay

Docker Secret Management

上面的 docker-compose.yml 中包含数据库密码等敏感信息,类似的信息有:用户名密码、SSH Key、TLS认证和任何不想让其它人看到的数据。对于这类似信息我们需要通过加密的方式进行存储同时 Service 还可以获取

# 从文件创建
docker secret create my-pw password.txt
# 命令行创建
echo "xxxxxx" | docker secret create my-pw -
# 查看和删除 
docker secret ls
docker secret rm
# 以 MySQL为例(--secret 指定前面创建的密钥,默认会在/run/secrets 下创建一个同名的文件并包含对应信息)
docker service create --name db --secret my-pw -e MYSQL_ROOT_PASSWORD_FILE=/run/secrets/my-pw mysql

# 同样以 Wordpress 为例,可以前面 Docker Stack 部署的docker-compose.yml文件进行如下修改
environment:
  WORDPRESS_DB_HOST: mysql
  WORDPRESS_DB_PASSWORD: root
# 修改为
secrets:
  - my-pw
environment:
  WORDPRESS_DB_HOST: mysql
  WORDPRESS_DB_PASSWORD_FILE: /run/secrets/my-pw

Service 更新

# 假设有一个名为 web 的 service,首先进行横向扩展,确保更新时服务不中断
docker service scale web=2
# image 更新
docker service update --image xxx/xxx web
# 端口更新
docker service update --publish-rm 8080:5000 --publish-add 8888:5000 web

DevOps初体验—Docker Cloud和Docker企业版

Docker Cloud

CaaS(Container-as-a-Service)

Docker Cloud:提供容器的管理、编排、部署的托管服务

主要模块:关联云服务商、添加节点行为、创建服务、创建 Stack、Image 管理

企业版安装

Docker Store 中申请30天试用,

Docker EE安装方法参见文档(以 CentOS为例)

安装 UCP

注:测试安装时发现版本仅为17.06.2,当前新版的 UCP 需要18以上的企业版,因而选择低版本兼容的 UCP

docker container run --rm -it --name ucp \
  -v /var/run/docker.sock:/var/run/docker.sock \
  docker/ucp:2.2.4 install \
  --host-address <node-ip-address> \
  --interactive

UCP(Universal Control Plane) 相当于一个网页版的 Swarm,安装完成后可通过 https://<node-ip-address>:443,根据安装时设置的用户名密码登录并上传后台下载的证书

点击 Nodes>Add Node,在 worker 节点服务器上执行生成的docker swarm join 代码段

Docker UCP

DTR安装

admin>Admin Settings>Docker Trusted Registry,选择 DTR EXTERNAL URL 和UCP NODE,勾选Disable TLS Verification For UCP,根据生成的docker run -it --rm docker/dtr install...命令在对应的主机上运行

以创建名为 demo 的 Repository 为例:

docker tag image-name:latest dtr.ip.addr/admin/demo
docker login dtr.ip.addr
docker push dtr.ip.addr/admin/demo

此外在 System>Security中 Enable Sanning 用于开启对镜像的安全扫描功能,此时即可对仓库中的镜像进行安全扫描:

DTS仓库&扫描

容器编排Kubernetes

Kubternetes架构

Minikube

使用 minikube 进行安装单节点 K8S集群

brew cask install minikube
# 启动
minikube start
# 查看设置及上下文
kubectl config view
kubectl config get-contexts
kubectl cluster-info
# 进入节点
minikube ssh

K8S最小调度单位 Pod,一个 Pod 共享一个 Namespace

# 创建 Pod
kubectl create -f xxx.yml
# 删除 Pod
kubectl delete -f xxx.yml
# 查看 Pod
kubectl get pods
# 显示更多信息
kubectl get pods -o wide
# 进入 Pod
kubectl exec -it xxx sh
# 查看 Pod 详细信息
kubectl describe pods xxx
# 端口转发,以 Nginx pod 为例
kubectl port-forward nginx 8080:80

# ReplicationController
# apiVersion: v1
# kind: ReplicationController
# 查看
kubectl get rc
# 扩展
kubectl scale rc nginx --replicas=2

# ReplicaSet
# apiVersion: apps/v1
# kind: ReplicaSet
# 查看
kubectl get rs
# 扩展
kubectl scale rs nginx --replicas=2 

# Deployment 
# apiVersion: apps/v1
# kind: Deployment
kubectl get deployment
kubectl get deployment -o wide
kubectl get pods
# 设置镜像(更新操作)
kubectl set image deployment nginx-deployment nginx=nginx:1.13
# 查看历史记录
kubectl rollout history deployment nginx-deployment
# 回复到上一个版本
kubectl rollout undo deployment nginx-deployment
# 创建 service 供外部访问及查看端口
kubectl expose deployment nginx-deployment --type=NodePort
kubectl get svc

Tectonic

使用Tectonic 搭建多节点集群

kubectl expose命令会给 Pod 创建 Service 供外部访问,Service 主要有三种类型:ClusterIP, NodePort, 外部的LoadBalancer(kubectl expose 通过--type 指定); 也可以使用 DNS,但需要 DNS 的 add-on

容器的的运维和监控

docker top
docker state

Weave Scope

sudo curl -L git.io/scope -o /usr/local/bin/scope
sudo chmod a+x /usr/local/bin/scope
scope launch
Weave Scope

heapster

InfluxDB, Grafana

minikube addons list
minikube addons enable heapster
# 重启
minikube stop
minikube start --extra-config=controller-manager.HorizontalPodAutoscalerUseRESTClients=false
# 自动横向扩展
# 运行镜像并暴露端口
kubectl run php-apache --image=k8s.gcr.io/hpa-example --requests=cpu=200m --expose --port=80
# 创建 HPA( Horizontal Pod Autoscaler),指定最小和最大数量,超过50%后就会扩展
kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10

# 查看
kubectl get deployment php-apache
kubectl get horizontalpodautoscaler
kubectl get svc

# 删除部署
kubectl delete deployment php-apache
kubectl delete svc php-apache
kubectl delete hpa php-apache

Horizontal Pod Autoscaler Walkthrough

日志采集展示

ELK Stack(ElasticSearch+Logstash+Kibana)

  • Fluentd(log 转发)
  • ElasticSearch(log Index)
  • Kibana(log 可视化)
  • LogTrail(log UI 查看)

本地搭建集群:kubeadm

相应 yml 文件(替换成对应版本):fluentd-elastisearch

集群监控方案(Pull 数据):https://prometheus.io/

Docker+DevOps实战—过程和工具

基本流程参见容器的的运维和监控部分的图片

安装 GitLab,参见Jenkins+Ansible+GitLab自动化部署三剑客

GitLab CI 服务器搭建

# 安装 Docker
curl -sSL https://get.docker.com/ | sh
# 安装 gitlab ci runner
curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-ci-multi-runner/script.rpm.sh | sudo bash
sudo yum install gitlab-ci-multi-runner -y
# 查看是否运行正常
sudo gitlab-ci-multi-runner status
# 设置 Docker 权限
sudo usermod -aG docker gitlab-runner
sudo service docker restart
sudo gitlab-ci-multi-runner restart

# 注册
sudo gitlab-ci-multi-runner register
# 输入 GitLab 地址和 token(项目页>Settings>CI/CD>Runners 下的Set up a specific Runner manually
中)
# 设置完成后在同一版块的Runners activated for this project中会发现新增的Runner,激活并在项目下添加.gitlab-ci.yml文件测试,结果在CI/CD>Pipelines 中查看

Settings>Repository>Protected Branches可设置禁止 master 分支的 push 行为

Repository>Branches 创建新分支(如 dev)

Settings>General>Merge Request 可进行相关限制

git fetch
git checkout dev
git push origin dev
# Merge Requests 中进行提交

常见问题

1、Error restarting cluster: restarting kube-proxy: waiting for kube-proxy to be up for configmap update: timed out waiting for the condition

# 删除重新执行
minikube delete
minikube start

原文链接:Alan Hou 的个人博客

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容