深入剖析Kubernetes学习笔记:深入理解镜像(08)
一、Python 应用案例环境
[root@k8s-node1 Flask]# pwd
/opt/Dockerfile/Flask
[root@k8s-node1 Flask]# ll
total 12
-rw-r--r-- 1 root root 352 Feb 1 10:08 app.py
-rw-r--r-- 1 root root 518 Feb 1 10:20 Dockerfile
-rw-r--r-- 1 root root 6 Feb 1 10:09 requirements.txt
[root@k8s-node1 Flask]# cat app.py
from flask import Flask
import socket
import os app = Flask(__name__) @app.route('/')
def hello():
html = "<h3>Hello {name}!</h3>" \
"<b>Hostname:</b> {hostname}<br/>"
return html.format(name=os.getenv("NAME", "world"), hostname=socket.gethostname()) if __name__ == "__main__":
app.run(host='0.0.0.0', port=80)
[root@k8s-node1 Flask]# cat requirements.txt
Flask
[root@k8s-node1 Flask]# cat Dockerfile
# 使用官方提供的 Python 开发镜像作为基础镜像
FROM python:2.7-slim # 将工作目录切换为 /app
WORKDIR /app # 将当前目录下的所有内容复制到 /app 下
ADD . /app # 使用 pip 命令安装这个应用所需要的依赖
RUN pip install --trusted-host pypi.python.org -r requirements.txt # 允许外界访问容器的 80 端口
EXPOSE 80 # 设置环境变量
ENV NAME World # 设置容器进程为:python app.py,即:这个 Python 应用的启动命令
CMD ["python", "app.py"]
Dockerfile的设计思想,是使用一些标准的原语(即大写高亮的词语),描述我们所要构建的Docker镜像,并且这些原语,都是按顺序处理的
需要注意的是,Dockerfile中的每个原语执行后,都会生成一个对应的镜像层
[root@k8s-node1 Flask]# docker images|grep docker.io/python
docker.io/python
二、启动容器以及相关操作
1、启动容器
$ docker run -p 4000:80 helloworld
2、查看进程
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED
4ddf4638572d helloworld "python app.py" 10 seconds ago
3、测试是否可用
$ curl http://localhost:4000
<h3>Hello World!</h3><b>Hostname:</b> 4ddf4638572d<br/>
4、上传镜像到仓库
[root@k8s-node1 ~]# docker exec -it 900e7b6e1984 /bin/sh#
# touch test.txt#
# exit#
[root@k8s-node1 ~]# docker tag helloworld 10.0.128.4:500/helloworld:v1#
[root@k8s-node1 ~]# docker push 10.0.128.4:500/helloworld:v1#
The push refers to a repository [10.0.128.4:500/helloworld]#
Get https://10.0.128.4:500/v1/_ping: dial tcp 10.0.128.4:500: getsockopt: connection refused "/bin/sh" 2 days ago Exited (137) 2 days ago grave_mclean#
三、docker exec 是怎么做到进入容器里的呢?
1、docker exec 的实现原理
[root@k8s-node1 Flask]# docker exec -it 43c49903582e /bin/sh
# pwd
/app
# ls
Dockerfile app.py requirements.txt test.txt
这里,我使用了docker exec 命令进入到了容器当中,在了解了Linux Namespace的隔离机制后,你应该会很自然地想到一个问题
docker exec 是怎么做到进入容器里的呢?
[root@k8s-node1 Flask]# docker inspect --format '{{ .State.Pid }}' 43c49903582e
2400
[root@k8s-node1 opt]# ls -l /proc/2400/ns
total 0
lrwxrwxrwx 1 root root 0 Feb 20 17:20 ipc -> ipc:[4026532495]
lrwxrwxrwx 1 root root 0 Feb 20 17:19 mnt -> mnt:[4026532493]
lrwxrwxrwx 1 root root 0 Feb 20 17:19 net -> net:[4026532498]
lrwxrwxrwx 1 root root 0 Feb 20 17:20 pid -> pid:[4026532496]
lrwxrwxrwx 1 root root 0 Feb 20 17:23 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Feb 20 17:20 uts -> uts:[4026532494]
这也就意味着:一个进程,可以选择加入到某个进程已有的 Namespace 当中,从而达到“进入”这个进程所在容器的目的,这正是 docker exec 的实现原理
2、docker exec 的实现原理刨析实验
1、依赖文件
_startmainopen@@GLIBC_2.2.5perror@@GLIBC_2.2.5_Jv_RegisterClassesexecvp@@GLIBC_2.2.5exit@@GLIBC_2.2.5__TMC_END___ITM_registerTMCloneTable_init
[root@k8s-node1 opt]# cat set_ns.c
#define _GNU_SOURCE
#include <fcntl.h>
#include <sched.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h> #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE);} while (0) int main(int argc, char *argv[]) {
int fd; fd = open(argv[1], O_RDONLY);
if (setns(fd, 0) == -1) {
errExit("setns");
}
execvp(argv[2], &argv[2]);
errExit("execvp");
}
2、执行
[root@k8s-node1 opt]# gcc -o set_ns set_ns.c
[root@k8s-node1 opt]# ./set_ns /proc/2400/ns/net /bin/bash
[root@k8s-node1 opt]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.16.6.2 netmask 255.255.255.0 broadcast 0.0.0.0
inet6 fe80::42:acff:fe10:602 prefixlen 64 scopeid 0x20<link>
ether 02:42:ac:10:06:02 txqueuelen 0 (Ethernet)
RX packets 8 bytes 648 (648.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 8 bytes 648 (648.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
3、查看进程的进程的 Namespace
[root@k8s-node1 opt]# ps aux|grep /bin/bash
root 2615 0.1 0.0 116204 2876 pts/0 S 17:28 0:00 /bin/bash
root 2652 0.0 0.0 112660 972 pts/0 R+ 17:28 0:00 grep --color=auto /bin/bash
[root@k8s-node1 opt]# ls -l /proc/2615/ns/net
lrwxrwxrwx 1 root root 0 Feb 20 17:30 /proc/2615/ns/net -> net:[4026532498]
[root@k8s-node1 opt]# ls -l /proc/2400/ns/net
lrwxrwxrwx 1 root root 0 Feb 20 17:19 /proc/2400/ns/net -> net:[4026532498]
转了一个大圈子,我其实是为你详细解读了这个操作背后,linux namespace更具体的工作原理
这种通过操作系统进程相关的知识,逐步刨析Docker容器的方法,是理解容器的一个关键思路,希望你一定要掌握
深入剖析Kubernetes学习笔记:深入理解镜像(08)的更多相关文章
- 深入剖析Kubernetes学习笔记:深入理解镜像(07)
一.容器里的进程看到的文件系统又是什么样子呢? 1.你会看到好多宿主机的文件 [root@k8s-master ~]# vim ns.c [root@k8s-master ~]# gcc -o nl ...
- 深入剖析Kubernetes学习笔记:开篇词(00)
一.关于Kubernetes初学的疑惑 就在这场因"容器"而起的技术变革中,kubernetes项目已经成为容器技术的事实标准,重新定义了基础设置领域对应用编排与管理的种种可能 1 ...
- 深入剖析Kubernetes学习笔记:预习篇(01-04)
01 初出茅庐 1.PaaS 项目被大家接纳的一个主要原因? 就是它提供了一种名叫"应用托管". 2.像 Cloud Foundry 这样的 PaaS 项目,最核心的组件是? 一套 ...
- 深入剖析Kubernetes学习笔记:容器基础(05-06)
05 :从进程说起 1.容器本身没有价值,有价值的是"容器编排" 2.什么是进程? 一旦"程序"被执行起来,它就从磁盘上的二进制文件,变成 1.计算机内存中的数 ...
- Kubernetes 学习笔记(一):基础概念
个人笔记,仅本人查阅使用,不保证正确. 零.微服务 微服务架构专注于应用解耦合,通过将应用彻底地组件化和服务化,每个微服务只包含一个非常小的功能,比如权限管理.日志收集等等.由这一组微服务组合起来,提 ...
- Kubernetes学习笔记(八):Deployment--声明式的升级应用
概述 本文核心问题是:如何升级应用. 对于Pod的更新有两种策略: 一是删除全部旧Pod之后再创建新Pod.好处是,同一时间只会有一个版本的应用存在:缺点是,应用有一段时间不可用. 二是先创建新Pod ...
- 微信小程序开发:学习笔记[7]——理解小程序的宿主环境
微信小程序开发:学习笔记[7]——理解小程序的宿主环境 渲染层与逻辑层 小程序的运行环境分成渲染层和逻辑层. 程序构造器
- Kubernetes学习笔记(四):服务
服务介绍 服务是一种为一组相同功能的pod提供单一不变接入点的资源.当服务存在时,他的IP和端口不会改变.客户端通过IP和端口建立连接,这些连接会被路由到任何一个pod上.如此,客户端不需要知道每个单 ...
- Kubernetes学习笔记之认识Kubernetes组件
前言:笔记知识点来源于Kubernetes官方文档说明,链接:https://kubernetes.io/docs/concepts/overview/components/ ,本记录仅仅是学习笔记记 ...
随机推荐
- Python模块time、datetime
模块: 模块是一系列常用功能的集合体,一个py文件就是一个模块. 一.模块的作用: 1.从文件级别组织程序,方便管理,随着程序的发展,功能越来越多,我们通常将程序分成一个个py文件,这样做程序的结构更 ...
- 复制命令(COPY)
COPY 命令: // 描述: 将一个或多个文件从一个位置复制到另一个位置. ### 注意:如果想复制文件夹,请使用 XCOPY . // 语法: copy [/a] [/b] [/d] [/v] ...
- LeetCode算法题-To Lower Case(Java实现)
这是悦乐书的第301次更新,第320篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第169题(顺位题号是709).实现具有字符串参数str的函数ToLowerCase() ...
- SQL LEN() 函数
LEN() 函数 LEN 函数返回文本字段中值的长度. SQL LEN() 语法 SELECT LEN(column_name) FROM table_name SQL LEN() 实例 我们拥有下面 ...
- 将List按照指定大小等分的几种实现方式和效率对比及优化
今天碰到一个需求,定时任务,批量从表里取数据并做一些其他操作然后再存表,每次取1000条,由于计算过程比较耗时所以要起多个线程同时跑,需要将List按照指定大小等分,如每100条数据起一个线程,若最后 ...
- 一人撸PaaS之“应用”
[什么是“应用”] 应用,如果按名词理解就是类似于可以使用的功能,比如一个App应用.事实上,一个应用包含了大量的交互功能以丰富我们的日常学习和生活. 我们这里的应用指的是一系列功能的集合,可以理解为 ...
- python scapy dns 包字段解析
qr: 0表示查询报文,1表示响应报文opcode: 通常值为0(标准查询),其他值为1(反向查询)和2(服务器状态请求).aa: 表示授权回答(authoritative answer)tc: ...
- Oracle物化视图的创建及使用
oracle物化视图 一.oracle物化视图基本概念 物化视图首先需要创建物化视图日志, oracle依据用户创建的物化视图日志来创建物化视图日志表, 物化视图日志表的名称为mlog$_后面跟 ...
- 使用lombok自动生成链式调用
本文转载:使用 Lombok 自动生成 Getter and Setter
- PhotoShop不用魔棒、钢笔 建立较平整的选区 P进电脑屏幕里
不用魔棒.抽出.钢笔等,还可以直接变形图建立调整选区,这种方法比钢笔抽出感觉简单一些,比魔棒仔细一些. 抽出或钢笔:抽出弄错了偏移了还要擦除,调整笔刷,抽出后可能还有毛边,需要用橡皮擦除: 钢笔,错了 ...