为了做好运维面试路上的助攻手,特整理了上百道 【运维技术栈面试题集锦】 ,让你面试不慌心不跳,高薪offer怀里抱!
这次整理的面试题,小到shell、MySQL,大到K8s等云原生技术栈,不仅适合运维新人入行面试需要,还适用于想提升进阶跳槽加薪的运维朋友。
本份面试集锦涵盖了
- 174 道运维工程师面试题
- 128道k8s面试题
- 108道shell脚本面试题
- 200道Linux面试题
- 51道docker面试题
- 35道Jenkis面试题
- 78道MongoDB面试题
- 17道ansible面试题
- 60道dubbo面试题
- 53道kafka面试
- 18道mysql面试题
- 40道nginx面试题
- 77道redis面试题
- 28道zookeeper
总计 1000+ 道面试题, 内容 又全含金量又高
- 174道运维工程师面试题
1、什么是运维?
2、在工作中,运维人员经常需要跟运营人员打交道,请问运营人员是做什么工作的?
3、现在给你三百台服务器,你怎么对他们进行管理?
4、简述raid0 raid1raid5二种工作模式的工作原理及特点
5、LVS、Nginx、HAproxy有什么区别?工作中你怎么选择?
6、Squid、Varinsh和Nginx有什么区别,工作中你怎么选择?
7、Tomcat和Resin有什么区别,工作中你怎么选择?
8、什么是中间件?什么是jdk?
9、讲述一下Tomcat8005、8009、8080三个端口的含义?
10、什么叫CDN?
11、什么叫网站灰度发布?
12、简述DNS进行域名解析的过程?
13、RabbitMQ是什么东西?
14、讲一下Keepalived的工作原理?
15、讲述一下LVS三种模式的工作过程?
16、mysql的innodb如何定位锁问题,mysql如何减少主从复制延迟?
17、如何重置mysql root密码?
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
#endif
#ifdef CONFIG_CGROUPS
.cgroup_ns = &init_cgroup_ns,
#endif
};
init\_nsproxy定义了初始的全局命名空间,其中维护了指向各个子系统初始化的命名空间对象的指针。
### 2.2 init\_uts\_ns
struct new_utsname {
char sysname[__NEW_UTS_LEN + 1];
char nodename[__NEW_UTS_LEN + 1];
char release[__NEW_UTS_LEN + 1];
char version[__NEW_UTS_LEN + 1];
char machine[__NEW_UTS_LEN + 1];
char domainname[__NEW_UTS_LEN + 1];
};
这些字符串存储了系统名Linux,发行版,内核版本,机器等等,可以通过uname查看,也可以在/proc/sys/kernel/下查看:
![在这里插入图片描述](https://img-blog.csdnimg.cn/797fac39314b40c4a39bfff308e0f925.png)
struct uts_namespace {
struct kref kref;
struct new_utsname name;
struct user_namespace *user_ns;
struct ucounts *ucounts;
struct ns_common ns;
};
extern struct uts_namespace init_uts_ns;
struct uts_namespace init_uts_ns = {
.kref = {
.refcount = ATOMIC_INIT(2),
},
.name = {
.sysname = UTS_SYSNAME,
.nodename = UTS_NODENAME,
.release = UTS_RELEASE,
.version = UTS_VERSION,
.machine = UTS_MACHINE,
.domainname = UTS_DOMAINNAME,
},
.user_ns = &init_user_ns,
.ns.inum = PROC_UTS_INIT_INO,
#ifdef CONFIG_UTS_NS
.ns.ops = &utsns_operations,
#endif
};
EXPORT_SYMBOL_GPL(init_uts_ns);
init\_uts\_ns是uts\_ns的初始化配置,相关的预处理器常数在内核中各处定义,通过编译内核顶层Makefile动态生成。
系统名是固定的:
#define UTS_SYSNAME “Linux”
## 三、创建namespace
### 3.1 fork
以fork为例:
SYSCALL_DEFINE0(fork)
–>_do_fork()
–>copy_process()
–>copy_namespaces()
–>create_new_namespaces()
### 3.2 copy\_namespaces
/*
* called from clone. This now handles copy for nsproxy and all
* namespaces therein.
*/
int copy_namespaces(unsigned long flags, struct task_struct *tsk)
{
struct nsproxy *old_ns = tsk->nsproxy;
struct user_namespace *user_ns = task_cred_xxx(tsk, user_ns);
struct nsproxy *new_ns;
if (likely(!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
CLONE_NEWPID | CLONE_NEWNET |
CLONE_NEWCGROUP)))) {
get\_nsproxy(old_ns);
return 0;
}
if (!ns\_capable(user_ns, CAP_SYS_ADMIN))
return -EPERM;
/\*
* CLONE_NEWIPC must detach from the undolist: after switching
* to a new ipc namespace, the semaphore arrays from the old
* namespace are unreachable. In clone parlance, CLONE_SYSVSEM
* means share undolist with parent, so we must forbid using
* it along with CLONE_NEWIPC.
*/
if ((flags & (CLONE_NEWIPC | CLONE_SYSVSEM)) ==
(CLONE_NEWIPC | CLONE_SYSVSEM))
return -EINVAL;
new_ns = create\_new\_namespaces(flags, tsk, user_ns, tsk->fs);
if (IS\_ERR(new_ns))
return PTR\_ERR(new_ns);
tsk->nsproxy = new_ns;
return 0;
}
如果 clone 的参数里面没有 CLONE\_NEWNS | CLONE\_NEWUTS | CLONE\_NEWIPC | CLONE\_NEWPID | CLONE\_NEWNET | CLONE\_NEWCGROUP,就返回原来的 namespace,调用 get\_nsproxy。
get\_nsproxy函数只是将struct nsproxy成员的count加1。
static inline void get_nsproxy(struct nsproxy *ns)
{
atomic_inc(&ns->count);
}
相对应有个函数put\_nsproxy将struct nsproxy成员的count减1,这个函数每次减1时会判断count是否等于0,等于0就释放掉调用free\_nsproxy释放掉命名空间资源。
static inline void put_nsproxy(struct nsproxy *ns)
{
if (atomic_dec_and_test(&ns->count)) {
free_nsproxy(ns);
}
}
get\_nsproxy 和 put\_nsproxy 操作类似于C++中的智能指针操作。
### 3.3 create\_new\_namespaces
如果 clone 的参数里面有 CLONE\_NEWNS | CLONE\_NEWUTS | CLONE\_NEWIPC | CLONE\_NEWPID | CLONE\_NEWNET | CLONE\_NEWCGROUP标志位,调用create\_new\_namespaces
/*
* Create new nsproxy and all of its the associated namespaces.
* Return the newly created nsproxy. Do not attach this to the task,
* leave it to the caller to do proper locking and attach it to task.
*/
static struct nsproxy *create_new_namespaces(unsigned long flags,
struct task_struct *tsk, struct user_namespace *user_ns,
struct fs_struct *new_fs)
{
struct nsproxy *new_nsp;
int err;
new_nsp = create\_nsproxy();
if (!new_nsp)
return ERR\_PTR(-ENOMEM);
new_nsp->mnt_ns = copy\_mnt\_ns(flags, tsk->nsproxy->mnt_ns, user_ns, new_fs);
if (IS\_ERR(new_nsp->mnt_ns)) {
err = PTR\_ERR(new_nsp->mnt_ns);
goto out_ns;
}
new_nsp->uts_ns = copy\_utsname(flags, user_ns, tsk->nsproxy->uts_ns);
if (IS\_ERR(new_nsp->uts_ns)) {
err = PTR\_ERR(new_nsp->uts_ns);
goto out_uts;
}
new_nsp->ipc_ns = copy\_ipcs(flags, user_ns, tsk->nsproxy->ipc_ns);
if (IS\_ERR(new_nsp->ipc_ns)) {
err = PTR\_ERR(new_nsp->ipc_ns);
goto out_ipc;
}
new_nsp->pid_ns_for_children =
copy\_pid\_ns(flags, user_ns, tsk->nsproxy->pid_ns_for_children);
if (IS\_ERR(new_nsp->pid_ns_for_children)) {
err = PTR\_ERR(new_nsp->pid_ns_for_children);
goto out_pid;
}
new_nsp->cgroup_ns = copy\_cgroup\_ns(flags, user_ns,
tsk->nsproxy->cgroup_ns);
if (IS\_ERR(new_nsp->cgroup_ns)) {
err = PTR\_ERR(new_nsp->cgroup_ns);
goto out_cgroup;
}
new_nsp->net_ns = copy\_net\_ns(flags, user_ns, tsk->nsproxy->net_ns);
if (IS\_ERR(new_nsp->net_ns)) {
err = PTR\_ERR(new_nsp->net_ns);
goto out_net;
}
return new_nsp;
......
}
创建新的nsproxy及其所有关联的名称空间,返回新创建的nsproxy。
#### 3.3.1 copy\_utsname
比如copy\_utsname:如果没有标志位CLONE\_NEWUTS,则返回old\_ns,如果设置了创建新的new\_ns。
// linux-4.10.1/kernel/utsname.c
/*
* Copy task tsk’s utsname namespace, or clone it if flags
* specifies CLONE_NEWUTS. In latter case, changes to the
* utsname of this process won’t be seen by parent, and vice
* versa.
*/
struct uts_namespace *copy_utsname(unsigned long flags,
struct user_namespace *user_ns, struct uts_namespace *old_ns)
{
struct uts_namespace *new_ns;
BUG\_ON(!old_ns);
get\_uts\_ns(old_ns);
if (!(flags & CLONE_NEWUTS))
return old_ns;
new_ns = clone\_uts\_ns(user_ns, old_ns);
put\_uts\_ns(old_ns);
return new_ns;
}
#### 3.3.2 copy\_ipcs
比如copy\_ipcs:
struct ipc_namespace *copy_ipcs(unsigned long flags,
struct user_namespace *user_ns, struct ipc_namespace *ns)
{
if (!(flags & CLONE_NEWIPC))
return get_ipc_ns(ns);
return create_ipc_ns(user_ns, ns);
}
如果没有设置标志位CLONE\_NEWIPC,调用get\_ipc\_ns将tsk->nsproxy->ipc\_ns->count加1。
static inline struct ipc_namespace *get_ipc_ns(struct ipc_namespace *ns)
{
if (ns)
atomic_inc(&ns->count);
return ns;
}
如果有标志位CLONE\_NEWIPC,调用 create\_ipc\_ns创建新的ipc\_namespace命名空间。
#### 3.3.3 copy\_pid\_ns
如果没有设置标志位 CLONE\_NEWPID,则返回老的 pid namespace。
// linux-4.10.1/kernel/pid_namespace.c
struct pid_namespace *copy_pid_ns(unsigned long flags,
struct user_namespace *user_ns, struct pid_namespace *old_ns)
{
if (!(flags & CLONE_NEWPID))
return get_pid_ns(old_ns);
if (task_active_pid_ns(current) != old_ns)
return ERR_PTR(-EINVAL);
return create_pid_namespace(user_ns, old_ns);
}
如果设置了,就调用 create\_pid\_namespace,创建新的 pid namespace。采用slab分配器分配struct pid\_namespace对象。
// linux-4.10.1/kernel/pid_namespace.c
static struct pid_namespace *create_pid_namespace(struct user_namespace *user_ns,
struct pid_namespace *parent_pid_ns)
{
…
struct pid_namespace *ns = kmem_cache_zalloc(pid_ns_cachep, GFP_KERNEL);
…
}
static inline void *kmem_cache_zalloc(struct kmem_cache *k, gfp_t flags)
{
return kmem_cache_alloc(k, flags | __GFP_ZERO);
}
#### 3.3.4 copy\_cgroup\_ns
如果没有设置标志位 CLONE\_NEWCGROUP,则返回老的 struct cgroup\_namespace,old\_ns。
// linux-4.10.1/kernel/cgroup.c
struct cgroup_namespace *copy_cgroup_ns(unsigned long flags,
struct user_namespace *user_ns,
struct cgroup_namespace *old_ns)
{
struct cgroup_namespace *new_ns;
struct ucounts *ucounts;
struct css_set *cset;
BUG\_ON(!old_ns);
if (!(flags & CLONE_NEWCGROUP)) {
get\_cgroup\_ns(old_ns);
return old_ns;
}
/\* Allow only sysadmin to create cgroup namespace. \*/
if (!ns\_capable(user_ns, CAP_SYS_ADMIN))
return ERR\_PTR(-EPERM);
ucounts = inc\_cgroup\_namespaces(user_ns);
if (!ucounts)
return ERR\_PTR(-ENOSPC);
/\* It is not safe to take cgroup\_mutex here \*/
spin\_lock\_irq(&css_set_lock);
cset = task\_css\_set(current);
get\_css\_set(cset);
spin\_unlock\_irq(&css_set_lock);
new_ns = alloc\_cgroup\_ns();
if (IS\_ERR(new_ns)) {
put\_css\_set(cset);
dec\_cgroup\_namespaces(ucounts);
return new_ns;
}
new_ns->user_ns = get\_user\_ns(user_ns);
new_ns->ucounts = ucounts;
new_ns->root_cset = cset;
return new_ns;
}
如果设置标志位 CLONE\_NEWCGROUP,则调用alloc\_cgroup\_ns创建新的struct cgroup\_namespace,new\_ns。
// linux-4.10.1/kernel/cgroup.c
static struct cgroup_namespace *alloc_cgroup_ns(void)
{
struct cgroup_namespace *new_ns;
int ret;
new_ns = kzalloc(sizeof(struct cgroup\_namespace), GFP_KERNEL);
if (!new_ns)
return ERR\_PTR(-ENOMEM);
ret = ns\_alloc\_inum(&new_ns->ns);
if (ret) {
kfree(new_ns);
return ERR\_PTR(ret);
}
atomic\_set(&new_ns->count, 1);
new_ns->ns.ops = &cgroupns_operations;
return new_ns;
}
#### 3.3.5 copy\_net\_ns
如果没有设置标志位 CLONE\_NEWNET,则返回老的 old\_net。
// linux-4.10.1/net/core/net_namespace.c
struct net *copy_net_ns(unsigned long flags,
struct user_namespace *user_ns, struct net *old_net)
{
struct ucounts *ucounts;
struct net *net;
int rv;
//返回老的 old\_net
if (!(flags & CLONE_NEWNET))
return get\_net(old_net);
ucounts = inc\_net\_namespaces(user_ns);
if (!ucounts)
return ERR\_PTR(-ENOSPC);
//分配一个新的 struct net 结构
net = net\_alloc();
if (!net) {
dec\_net\_namespaces(ucounts);
return ERR\_PTR(-ENOMEM);
}
get\_user\_ns(user_ns);
......
//setup\_net runs the initializers for the network namespace object.
rv = setup\_net(net, user_ns);
if (rv == 0) {
rtnl\_lock();
list\_add\_tail\_rcu(&net->list, &net_namespace_list);
rtnl\_unlock();
}
......
return net;
}
如果设置标志位 CLONE\_NEWNET了,新建一个 network namespace。
copy\_net\_ns 会调用 net = net\_alloc(),分配一个新的 struct net 结构:
// linux-4.10.1/net/core/net_namespace.c
static struct kmem_cache *net_cachep;
static struct net *net_alloc(void)
{
struct net *net = NULL;
…
net = kmem_cache_zalloc(net_cachep, GFP_KERNEL);
…
}
然后调用 setup\_net 对新分配的 net 结构进行初始化,之后调用 list\_add\_tail\_rcu,将新建的 network namespace,添加到全局的 network namespace 列表 net\_namespace\_list 中。
// linux-4.10.1/net/core/net_namespace.c
LIST_HEAD(net_namespace_list);
EXPORT_SYMBOL_GPL(net_namespace_list);
rv = setup_net(net, user_ns);
if (rv == 0) {
rtnl_lock();
list_add_tail_rcu(&net->list, &net_namespace_list);
rtnl_unlock();
}
## 总结
Linux Namespace是Kernel的一个功能,它可以隔离一系列的系统资源,比如PID(Process ID)、User ID、Network等。
![在这里插入图片描述](https://img-blog.csdnimg.cn/6474e9b6e252457d8a882e489f7155af.png)
## 参考资料
### 最后的话
最近很多小伙伴找我要Linux学习资料,于是我翻箱倒柜,整理了一些优质资源,涵盖视频、电子书、PPT等共享给大家!
### 资料预览
给大家整理的视频资料:
![](https://img-blog.csdnimg.cn/img_convert/9f2aa5a41dbb6663b4a9b7707676f1cc.png)
给大家整理的电子书资料:
![](https://img-blog.csdnimg.cn/img_convert/829216d6cd3ef9e1175fd7fac6b234b3.png)
**如果本文对你有帮助,欢迎点赞、收藏、转发给朋友,让我有持续创作的动力!**
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化的资料的朋友,可以点击这里获取!](https://bbs.csdn.net/topics/618542503)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
Process ID)、User ID、Network等。
![在这里插入图片描述](https://img-blog.csdnimg.cn/6474e9b6e252457d8a882e489f7155af.png)
## 参考资料
### 最后的话
最近很多小伙伴找我要Linux学习资料,于是我翻箱倒柜,整理了一些优质资源,涵盖视频、电子书、PPT等共享给大家!
### 资料预览
给大家整理的视频资料:
[外链图片转存中...(img-GoH9MwIF-1715134392154)]
给大家整理的电子书资料:
[外链图片转存中...(img-UkHLjwB2-1715134392155)]
**如果本文对你有帮助,欢迎点赞、收藏、转发给朋友,让我有持续创作的动力!**
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化的资料的朋友,可以点击这里获取!](https://bbs.csdn.net/topics/618542503)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**