容器学习

docker背景

  1. 好处
    线上线下环境一致,沙盒更安全,虚拟化提升硬件效率 轻量级的隔离环境:层共享 易于版本控制 保持简单,尽量只用无状态的服务以及静态的配置,有状态的例如数据库啥的能独立出去就独立出去。

  2. 学习流程
    Docker basics->Define and deploy apps in Swarm Mode,可以看官网上的提示。

使用docker的行为

  1. 构建及保存镜像快照
  2. 上传镜像到仓库
  3. 下载镜像到宿主机
  4. 以容器方式运行镜像
  5. 将容器与别的服务连接
  6. 路由流量到容器中
  7. 将容器log发送到指定位置
  8. 监控容器

组件

  1. 构建系统
    关注dockerfile放哪,手动构建推送或者自动构建
  2. 镜像仓库
    关注docker镜像在哪里保存,私有仓库的建设
  3. 宿主机管理
    配置以及升级宿主机
  4. 配置管理
    如何定义容器的集群,如何处理宿主机和容器运行时的配置,如何管理密钥和机密信息
  5. 部署
    如何将容器放在宿主机上,如推送或者拉取
  6. 编排
    如何将容器组织成集群,在哪些服务器上运行容器,怎么调度服务器资源,怎么把流量给容器,容器公开和发现服务
  7. 日志
  8. 监控

入门

入门例子:搭建我的linux开发环境

在mac上开发,为了和线上环境一样,我也在本地搞了一个centOS的linux环境。再也不用vmware和virtualbox了

0. docker有点长,我更喜欢加个别名:alias dc="docker"到~/.zshrc  
1. docker search centOS  
2. docker pull centos  
(删除一个images:docker rmi centos:latest)
3. docker run -d --name vizCentOS --rm -ti centos /bin/bash :启动并进入,-d 表明在后台运行,而不是一退出就是关闭容器 --name 是指家名字, --rm是指退出时删除容器,这对于我以后长期在这个容器中使用centos是不好的,所以最好别加。-ti是以交互方式进入,其中t指tty,i是交互模式  
4. docker ps:加-a为显示所有的容器,加-l显示最近的容器,不加只显示现在还在运行的。  
5. docker start {CONTAINER ID}可以启动一个容器  
6. 以交互方式进入centOS: docker exec -ti {NAMES pensive_ritchie} /bin/bash  
   更简单的是直接:docker attach {container}
   所以修正后的是:docker run -d  -ti --name vizcentos centos

别的基础命令

  1. docker container ls -a
    查看所有的container,包括停了的
    1. docker diff {container}
      可以查看这个容器做了哪些操作 docker diff c48789d619b7 C /home A /home/test C /root A /root/.bash_history
  2. docker cp
    在主机与容器间复制文件 $ docker cp c48789d619b7:/home/test .
  3. docker logs {container}
    查看做了哪些操作

  4. 查看容器信息
    docer inspect {containerId}

  5. 挂载目录以入通信
    docker run -it --name myname --link AA:BB -v outPath:containerPath imageName --link 加上后可与对应的容器进行通信,BB就是hosts里面的地址 -v就是挂载

  6. docker attach {container}
    经常会有进入容器看文件的操作,有几种:一种是容器自带ssh,第二种是使用第三方工具,第三种是docker自带的attach和exec 加个回车进入容器内。这种方式其实不太好,中断sdtin会导致容器Stop.所以还是用docker exec -it {container} /bin/bash 会更好一些,前提是有这个/bin/bash在容器中。

  7. docker port {container}

 docker run -d -P --name web nginx
docker port web  
443/tcp -> 0.0.0.0:32768  
80/tcp -> 0.0.0.0:32769  
访问http://0.0.0.0:32769/是可以进入到nginx的欢迎页面的

docker的网络

docker run 创建 Docker 容器时,可以用 --net 选项指定容器的网络模式,Docker 有以下 4 种网络模式

  1. host 模式,使用 --net=host 指定
如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。
  1. container 模式,使用 --net=container:NAMEorID 指定。
这个模式指定新创建的容器和已经存在的一个容器共享一个Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过lo网卡设备通信。
  1. none 模式,使用 --net=none 指定
Docker容器拥有自己的Network Namespace,但是,并不为Docker容器进行任何网络配置。也就是说,这个Docker容器没有网卡、IP、路由等信息。需要我们自己为Docker容器添加网卡、配置IP等  
  1. bridge 模式,使用 --net=bridge 指定,默认设置。
此模式会为每一个容器分配Network Namespace、设置IP等,并将一个主机上的Docker容器连接到一个虚拟网桥上。

redis集群部署例子

Docker的设计就是尽量一个容器只运行一个进程。但是我们常用的应用服务是多个容器实现不同功能拼凑起来的,容器之间需要通信来汇聚成服务。所以我们需要构建集群。这个例子就是用已有的镜像来完成一个redis集群。

  1. 镜像
dc pull ubuntu  
dc pull redis  
  1. 按顺序启动
#启动redis,1主2从
dc run -it --name redis-master redis /bin/bash  
dc run -it --name redis-slave1 --link redis-master:master redis /bin/bash  
dc run -it --name redis-slave2 --link redis-master:master redis /bin/bash

#查看进程是否正常
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES  
240eb6b02a16        redis               "docker-entrypoint..."   5 minutes ago       Up 5 minutes        6379/tcp                 redis-slave2  
031cccedfa2b        redis               "docker-entrypoint..."   5 minutes ago       Up 5 minutes        6379/tcp                 redis-slave1  
9a7e39aa46ef        redis               "docker-entrypoint..."   10 minutes ago      Up 6 minutes        6379/tcp                 redis-master

# 应用配置
需要一个redis.conf文件来设置
1. copy本地的redis.conf  
docker cp ~/temp/redis/redis-3.2.8/redis.conf 9a7e39aa46ef:/data/test/  
修改点:
daemonize yes  
pidfile /var/run/redis.pid

2. 进入到容器:  
docker attach 9a7e39aa46ef  
cd test  
which redis-server  
/usr/local/bin/redis-server
redis-server redis.conf

执行redis-cli看一下在容器内部是不是可以访问了:
127.0.0.1:6379> set a 1  
OK  
127.0.0.1:6379> get a  
"1"


3.继续修改slave  
在外部修改redis.conf:slaveof master 6379
copy到slave容器中:  
$ docker cp ~/temp/redis/redis-3.2.8/redis.conf 240eb6b02a16:/data/
$ docker cp ~/temp/redis/redis-3.2.8/redis.conf 031cccedfa2b:/data/

再分别启动slaver的redis-server:
root@240eb6b02a16:/data# redis-server redis.conf  
root@031cccedfa2b:/data# redis-server redis.conf

但这个时候发现在master主set a 1,在slaver上获取不到a。在slaver上看一下info replication, 发现有master_link_status:down。
于是查看了一下master的配置,有几处是需要修改的:
bind 0.0.0.0  
protected-mode no #否则不能从别的client连接过来  
daemonize yes #可能没啥影响,先开着吧  
master别加这行:slaveof master 6379(所以最好弄两配置文件否则容易copy错)

而slaver的配置是:
slaveof master 6379

然后分别再进入master和slaver,kill 原来的redis-server进程后,先后再启动,slaver启动时会报如下的log,就是真的启动成功了。
47:S 04 Apr 04:22:41.910 * Connecting to MASTER master:6379  
47:S 04 Apr 04:22:41.911 * MASTER <-> SLAVE sync started  
47:S 04 Apr 04:22:41.911 * Non blocking connect for SYNC fired the event.  
47:S 04 Apr 04:22:41.911 * Master replied to PING, replication can continue...  
47:S 04 Apr 04:22:41.912 * Partial resynchronization not possible (no cached master)  
47:S 04 Apr 04:22:41.913 * Full resync from master: eb63a014dde088fc0709a1d1cb437b65902a35d9:57  
47:S 04 Apr 04:22:41.969 * MASTER <-> SLAVE sync: receiving 76 bytes from master  
47:S 04 Apr 04:22:41.970 * MASTER <-> SLAVE sync: Flushing old data  
47:S 04 Apr 04:22:41.970 * MASTER <-> SLAVE sync: Loading DB in memory  
47:S 04 Apr 04:22:41.970 * MASTER <-> SLAVE sync: Finished with success

可以再到slaver2上重复一下

4. 测试一下redis  
在master机器上redis-cli,set aa 1,再到slaver上面 get aa,不是nil而是"1"就说明主从备份好了
注意一别关容器,2别关redis-server进程,可以新开iterm来搞或者后台执行。

原理初探

Docker使用了Linux的Namespaces技术来进行资源隔离,如PID Namespace隔离进程,Mount Namespace隔离文件系统,Network Namespace隔离网络等;通过cgroups实现资源限制;通过copy-on-write实现高效的文件操作。想要了解docker的实现,需要了解linux内核的技术细节。 目前这一部分暂时先不涉及

k8s集群化

k8s的命令

  1. kubectl get pod, 查看pod列表
  2. kubectl delete po mysql 删除pod,例如创建失败一直在卡着的话就可以使用这个删除
  3. kubectl describe pod mysql:查看pod详情
  4. kubectl create -f mysql.yaml:创建一个pod或者service
  5. kubectl get rc,service,deployment
  6. kubectl logs -f podName:查看pod的log
  7. kubectl get pods -o wide:查看pod的node,这个里面的NODE中的ip就是我们可以通过nodeport访问的ip.

例子:我需建立一个mysql的单机服务

1. 到aws上面申请EBS  
2. 创建pod文件  
apiVersion: v1  
kind: Pod  
metadata:  
  name: mysql
  labels:
    name: mysql
spec:  
  containers:
    - resources:
        limits:##这里没有cpu和内存的限制也需要加上这个字段不然会启不来
      image: mysql:5.7.18
      name: mysql
      env:
        - name: MYSQL_ROOT_PASSWORD
          value: yourpasswd
      ports:
        - containerPort: 3306
          name: mysql
      volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
  volumes:
  - name: mysql-persistent-storage
    awsElasticBlockStore:
      volumeID: vol-12345678910#这里需要写你的EBSvolumeID
      fsType: ext4

3. kubectl create -f mysql.ymal  
4. kubectl get pod 查看,如果没有running,看一下describe。有常见的错误可以搜索一下。有几种常见的:容器下载失败,没有limit字段,EBS id已经被别的挂载了例如放到某台机器上了。

1. 写service的yaml  
apiVersion: v1  
kind: Service  
metadata:  
  labels:
    name: mysql
  name: mysql
spec:  
  ports:
    - port: 3306
  selector:
    name: mysql

如果想绑定到一台机器上:
apiVersion: v1  
kind: Service  
metadata:  
  labels:
    name: mysql
  name: mysql
spec:  
  externalIPs:
    - 172.31.12.73#你想绑的那一台机器
  ports:
  - port: 3306
    targetPort: 3306
    protocol: TCP
  selector:
    name: mysql


6. create service  
kubectl create -f  mysql-service.yaml

7. 开放端口,自测的话同一集群的机器测试就好了。

备注

参考资料

  1. 官网
  2. docker中文指南

docker命令帮助

$ sudo docker   # docker 命令帮助

Commands:
    attach    Attach to a running container                 # 当前 shell 下 attach 连接指定运行镜像
    build     Build an image from a Dockerfile              # 通过 Dockerfile 定制镜像
    commit    Create a new image from a container's changes # 提交当前容器为新的镜像
    cp        Copy files/folders from the containers filesystem to the host path
              # 从容器中拷贝指定文件或者目录到宿主机中
    create    Create a new container                        # 创建一个新的容器,同 run,但不启动容器
    diff      Inspect changes on a container's filesystem   # 查看 docker 容器变化
    events    Get real time events from the server          # 从 docker 服务获取容器实时事件
    exec      Run a command in an existing container        # 在已存在的容器上运行命令
    export    Stream the contents of a container as a tar archive   
              # 导出容器的内容流作为一个 tar 归档文件[对应 import ]
    history   Show the history of an image                  # 展示一个镜像形成历史
    images    List images                                   # 列出系统当前镜像
    import    Create a new filesystem image from the contents of a tarball  
              # 从tar包中的内容创建一个新的文件系统映像[对应 export]
    info      Display system-wide information               # 显示系统相关信息
    inspect   Return low-level information on a container   # 查看容器详细信息
    kill      Kill a running container                      # kill 指定 docker 容器
    load      Load an image from a tar archive              # 从一个 tar 包中加载一个镜像[对应 save]
    login     Register or Login to the docker registry server   
              # 注册或者登陆一个 docker 源服务器
    logout    Log out from a Docker registry server         # 从当前 Docker registry 退出
    logs      Fetch the logs of a container                 # 输出当前容器日志信息
    port      Lookup the public-facing port which is NAT-ed to PRIVATE_PORT
              # 查看映射端口对应的容器内部源端口
    pause     Pause all processes within a container        # 暂停容器
    ps        List containers                               # 列出容器列表
    pull      Pull an image or a repository from the docker registry server
              # 从docker镜像源服务器拉取指定镜像或者库镜像
    push      Push an image or a repository to the docker registry server
              # 推送指定镜像或者库镜像至docker源服务器
    restart   Restart a running container                   # 重启运行的容器
    rm        Remove one or more containers                 # 移除一个或者多个容器
    rmi       Remove one or more images                 
              # 移除一个或多个镜像[无容器使用该镜像才可删除,否则需删除相关容器才可继续或 -f 强制删除]
    run       Run a command in a new container
              # 创建一个新的容器并运行一个命令
    save      Save an image to a tar archive                # 保存一个镜像为一个 tar 包[对应 load]
    search    Search for an image on the Docker Hub         # 在 docker hub 中搜索镜像
    start     Start a stopped containers                    # 启动容器
    stop      Stop a running containers                     # 停止容器
    tag       Tag an image into a repository                # 给源中镜像打标签
    top       Lookup the running processes of a container   # 查看容器中运行的进程信息
    unpause   Unpause a paused container                    # 取消暂停容器
    version   Show the docker version information           # 查看 docker 版本号
    wait      Block until a container stops, then print its exit code   
              # 截取容器停止时的退出状态值
Run 'docker COMMAND --help' for more information on a command.
comments powered by Disqus