0%

CentOS

1
2
yum install git -y
git clone https://github.com/csongyu/container-heap-size.git

8u121-jdk-alpine

构建镜像

1
./build_image.sh 8u121-jdk-alpine

运行镜像

默认配置

1
2
3
4
5
6
# JVM 基于 RAM 计算 -Xmx -Xms
./run_image.sh 8u121-jdk-alpine

Initial Memory (xms): 60mb
Max Memory (xmx): 832mb
VM Info: OpenJDK 64-Bit Server VM 25.121-b13

配置 --memory

1
2
3
4
5
6
7
8
9
10
11
12
# 旧版本 JVM 未感知到分配给容器的内存,错误计算 -Xmx -Xms
./run_image.sh 8u121-jdk-alpine 200m

Initial Memory (xms): 60mb
Max Memory (xmx): 832mb
VM Info: OpenJDK 64-Bit Server VM 25.121-b13

# 尝试申请 200mb 内存(软引用)
# 由于 JVM 错误计算 -Xmx,因此在达到容器内存限制(200mb)前未触发 GC(-Xmx 832mb,832mb > 200mb),导致 Docker 杀掉此进程
./run_image.sh 8u121-jdk-alpine 200m "" 200

Killed

配置 --memory 和 -Xmx -Xms

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 手动配置 -Xmx -Xms
./run_image.sh 8u121-jdk-alpine 200m "-Xmx100m -Xms100m"

Initial Memory (xms): 100mb
Max Memory (xmx): 94mb
VM Info: OpenJDK 64-Bit Server VM 25.121-b13

# 尝试申请 200mb 内存(软引用)
# 通过配置 -Xmx -Xms 防止 Docker 杀掉进程(-Xmx 100mb,100mb < 200mb)
./run_image.sh 8u121-jdk-alpine 200m "-Xmx100m -Xms100m" 200

Used Memory: 48mb
Initial Memory (xms): 100mb
Max Memory (xmx): 90mb

8u212-jdk-alpine

构建镜像

1
./build_image.sh 8u212-jdk-alpine

运行镜像

默认配置

1
2
3
4
5
6
# JVM 基于 RAM 计算 -Xmx -Xms
./run_image.sh 8u212-jdk-alpine

Initial Memory (xms): 60mb
Max Memory (xmx): 832mb
VM Info: OpenJDK 64-Bit Server VM 25.212-b04

配置 --memory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 新版本 JVM 感知到分配给容器的内存,正确计算 -Xmx -Xms
./run_image.sh 8u212-jdk-alpine 200m

Initial Memory (xms): 8mb
Max Memory (xmx): 96mb
VM Info: OpenJDK 64-Bit Server VM 25.212-b04

# 尝试申请 200mb 内存(软引用)
# 由于 JVM 正确计算 -Xmx, 因此在达到容器内存限制前触发 GC,防止 Docker 杀掉进程
./run_image.sh 8u212-jdk-alpine 200m "" 200

Used Memory: 32mb
Initial Memory (xms): 8mb
Max Memory (xmx): 96mb
VM Info: OpenJDK 64-Bit Server VM 25.212-b04

FetchType.LAZY

csongyu/jpa-fetch

branch: feature/FetchType.LAZY

where company_code=?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Hibernate: 
select
company0_.code as code1_1_0_,
company0_.name as name2_1_0_
from
company company0_
where
company0_.code=?
Hibernate:
select
employees0_.company_code as company_4_2_0_,
employees0_.id as id1_2_0_,
employees0_.id as id1_2_1_,
employees0_.code as code2_2_1_,
employees0_.company_code as company_4_2_1_,
employees0_.name as name3_2_1_
from
employee employees0_
where
employees0_.company_code=?

where company_code in (?,?)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
Hibernate: 
select
company0_.code as code1_1_,
company0_.name as name2_1_
from
company company0_
where
company0_.code in (
? , ?
)
Hibernate:
select
employees0_.company_code as company_4_2_0_,
employees0_.id as id1_2_0_,
employees0_.id as id1_2_1_,
employees0_.code as code2_2_1_,
employees0_.company_code as company_4_2_1_,
employees0_.name as name3_2_1_
from
employee employees0_
where
employees0_.company_code=?
Hibernate:
select
employees0_.company_code as company_4_2_0_,
employees0_.id as id1_2_0_,
employees0_.id as id1_2_1_,
employees0_.code as code2_2_1_,
employees0_.company_code as company_4_2_1_,
employees0_.name as name3_2_1_
from
employee employees0_
where
employees0_.company_code=?

FetchType.EAGER

csongyu/jpa-fetch

branch: feature/FetchType.EAGER

where company_code=?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Hibernate: 
select
company0_.code as code1_1_0_,
company0_.name as name2_1_0_,
employees1_.company_code as company_4_2_1_,
employees1_.id as id1_2_1_,
employees1_.id as id1_2_2_,
employees1_.code as code2_2_2_,
employees1_.company_code as company_4_2_2_,
employees1_.name as name3_2_2_
from
company company0_
left outer join
employee employees1_
on company0_.code=employees1_.company_code
where
company0_.code=?

where company_code in (?,?)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
Hibernate: 
select
company0_.code as code1_1_,
company0_.name as name2_1_
from
company company0_
where
company0_.code in (
? , ?
)
Hibernate:
select
employees0_.company_code as company_4_2_0_,
employees0_.id as id1_2_0_,
employees0_.id as id1_2_1_,
employees0_.code as code2_2_1_,
employees0_.company_code as company_4_2_1_,
employees0_.name as name3_2_1_
from
employee employees0_
where
employees0_.company_code=?
Hibernate:
select
employees0_.company_code as company_4_2_0_,
employees0_.id as id1_2_0_,
employees0_.id as id1_2_1_,
employees0_.code as code2_2_1_,
employees0_.company_code as company_4_2_1_,
employees0_.name as name3_2_1_
from
employee employees0_
where
employees0_.company_code=?

JOIN FETCH

csongyu/jpa-fetch

branch: feature/JOIN-FETCH

where company_code=?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Hibernate: 
select
company0_.code as code1_1_0_,
employees1_.id as id1_2_1_,
company0_.name as name2_1_0_,
employees1_.code as code2_2_1_,
employees1_.company_code as company_4_2_1_,
employees1_.name as name3_2_1_,
employees1_.company_code as company_4_2_0__,
employees1_.id as id1_2_0__
from
company company0_
inner join
employee employees1_
on company0_.code=employees1_.company_code
where
company0_.code=?

where company_code in (?,?)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Hibernate: 
select
company0_.code as code1_1_0_,
employees1_.id as id1_2_1_,
company0_.name as name2_1_0_,
employees1_.code as code2_2_1_,
employees1_.company_code as company_4_2_1_,
employees1_.name as name3_2_1_,
employees1_.company_code as company_4_2_0__,
employees1_.id as id1_2_0__
from
company company0_
inner join
employee employees1_
on company0_.code=employees1_.company_code
where
company0_.code in (
? , ?
)

@OneToMany N+1 SELECT

QUERIES FetchType.LAZY FetchType.EAGER JOIN FETCH
where company_code=? 2 1 1
where company_code in (?,?) 3 (N+1) 3 (N+1) 1

csongyu/jpa-fetch

branch: feature/@OneToOne

N+1 SELECT

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@Entity
@Data
@EqualsAndHashCode(of = {"code"})
public class Employee implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

private String name;

@Column(nullable = false, unique = true)
private String code;

// whatever FetchType is LAZY or EAGER
@OneToOne(mappedBy = "employee", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Address address;
}

@Entity
@Data
@ToString(exclude = {"employee"})
@EqualsAndHashCode(of = {"id"})
public class Address {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

private String city;

private String street;

@OneToOne
private Employee employee;
}
1
2
3
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
Set<Employee> findByCodeIn(Set<String> codes);
}
1
2
// employeeCodes size is 3, 3+1 SELECTs in total
final Set<Employee> employees = this.repository.findByCodeIn(employeeCodes);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
Hibernate: 
select
employee0_.id as id1_1_,
employee0_.code as code2_1_,
employee0_.name as name3_1_
from
employee employee0_
where
employee0_.code in (
? , ? , ?
)
Hibernate:
select
address0_.id as id1_0_1_,
address0_.city as city2_0_1_,
address0_.employee_id as employee4_0_1_,
address0_.street as street3_0_1_,
employee1_.id as id1_1_0_,
employee1_.code as code2_1_0_,
employee1_.name as name3_1_0_
from
address address0_
left outer join
employee employee1_
on address0_.employee_id=employee1_.id
where
address0_.employee_id=?
Hibernate:
select
address0_.id as id1_0_1_,
address0_.city as city2_0_1_,
address0_.employee_id as employee4_0_1_,
address0_.street as street3_0_1_,
employee1_.id as id1_1_0_,
employee1_.code as code2_1_0_,
employee1_.name as name3_1_0_
from
address address0_
left outer join
employee employee1_
on address0_.employee_id=employee1_.id
where
address0_.employee_id=?
Hibernate:
select
address0_.id as id1_0_1_,
address0_.city as city2_0_1_,
address0_.employee_id as employee4_0_1_,
address0_.street as street3_0_1_,
employee1_.id as id1_1_0_,
employee1_.code as code2_1_0_,
employee1_.name as name3_1_0_
from
address address0_
left outer join
employee employee1_
on address0_.employee_id=employee1_.id
where
address0_.employee_id=?

JOIN FETCH

1
2
3
4
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
@Query("from Employee e join fetch e.address where e.code in :code")
Set<Employee> queryByCodeIn(@Param("code") Set<String> codes);
}
1
2
// employeeCodes size is 3, only 1 SELECT in total
final Set<Employee> employees = this.repository.queryByCodeIn(employeeCodes);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Hibernate: 
select
employee0_.id as id1_1_0_,
address1_.id as id1_0_1_,
employee0_.code as code2_1_0_,
employee0_.name as name3_1_0_,
address1_.city as city2_0_1_,
address1_.employee_id as employee4_0_1_,
address1_.street as street3_0_1_
from
employee employee0_
inner join
address address1_
on employee0_.id=address1_.employee_id
where
employee0_.code in (
? , ? , ?
)

1. What is the docker command to find the current logging driver for a running container?

A. docker stats

B. docker info

C. docker config

D. docker inspect

2. When an application being managed by UCP fails, you would like a summary of all requests made to the UCP API in the hours leading up to the failure.

What must be configured correctly beforehand for this to be possible?

A. UCP audit logs must be set to the metadata or request level.

B. UCP logging levels must be set to the info or debug level.

C. All engines in the cluster must have their log driver set to the metadata or request level.

D. Set the logging level in the config object for the ucp-kube-api-server container to warning or higher.

Enable audit logging on UCP

Audit Logs capture all HTTP actions (GET, PUT, POST, PATCH, DELETE) to all UCP API, Swarm API and Kubernetes API endpoints that are invoked (except for the ignored list) and sent to Docker Engine via stdout. Creating audit logs is a UCP component that integrates with Swarm, K8s, and UCP APIs.

Logging Levels

None, Metadata, Request.

Benefits

Historical Troubleshooting - Audit logs are helpful in determining a sequence of past events that explain why an issue occured.

Security Analysis and Auditing - Security is one of the primary uses for audit logs. A full record of all user interactions with the container infrastructure gives your security team full visibility to questionable or attempted unauthorized accesses.

Chargeback - You can use audit logs and information about the resources to generate chargeback information.

Alerting - If there is a watch on an event stream or a notification created by the event, alerting features can be built on top of event tools that generate alerts for ops teams (PagerDuty, OpsGenie, Slack, or custom solutions).

Read more »

Practice

Pods

1
2
3
4
kubectl create namespace -h
kubectl config set-context --current --namespace=ckad
kubectl run -h
# --rm=false: If true, delete resources created in this command for attached containers.

ConfigMaps

Configure a Pod to Use a ConfigMap

Use envFrom to define all of the ConfigMap's data as container environment variables. The key from the ConfigMap becomes the environment variable name in the Pod.

1
2
3
4
5
kubectl create configmap -h
# --from-env-file
# Specify the path to a file to read lines of key=val pairs to create a configmap.
kubectl run -h
# --dry-run='none': Must be "none", "server", or "client". If client strategy, only print the object that would be sent, without sending it.

Secrets

Using Secrets as environment variables

1
2
3
kubectl create secret generic -h
# --from-file
# Specifying a directory will iterate each named file in the directory that is a valid secret key.

SecurityContext

Configure a Security Context for a Pod or Container

1
2
3
kubectl explain Pod.spec.securityContext
# fsGroup
# A special supplemental group that applies to all containers in a pod. Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod.

Resource Quotas

Resource Quotas

A resource quota, defined by a ResourceQuota object, provides constraints that limit aggregate resource consumption per namespace. It can limit the quantity of objects that can be created in a namespace by type, as well as the total amount of compute resources that may be consumed by resources in that namespace.

Resource Management for Pods and Containers

1
kubectl create quota -h

Service Accounts

Configure Service Accounts for Pods

1
2
3
kubectl explain Pod.spec
# serviceAccountName
# ServiceAccountName is the name of the ServiceAccount to use to run this pod.

Readiness and Liveness Probes

Configure Liveness, Readiness and Startup Probes

Labels

Labels and Selectors

Set-based label requirements allow filtering keys according to a set of values. Three kinds of operators are supported: in,notin and exists (only the key identifier).

1
kubectl label -h

Secrets

Using Secrets as files from a Pod

1
kubectl create deployment -h

Deployments

Rolling Back a Deployment

1
2
3
4
5
6
kubectl set image -h
kubectl rollout history -h
# --revision
# See the details, including podTemplate of the revision specified
kubectl scale -h
kubectl rollout undo -h

CronJob

1
kubectl create cronjob -h

Cron schedule syntax

Jobs History Limits

Service

Publishing Services (ServiceTypes)

1
2
# --rm
kubectl run <pod name> --image=busybox -it --rm --restart=Never -- <command>

Network Policies

The NetworkPolicy resource

podSelector: Each NetworkPolicy includes a podSelector which selects the grouping of pods to which the policy applies. An empty podSelector selects all pods in the namespace.

Init Containers

Configure Pod Initialization

Helm

Installing Helm

Helm Completion

Helm Repo

1
2
helm repo add stable https://charts.helm.sh/stable
helm repo add bitnami https://charts.bitnami.com/bitnami

Helm Search

Helm Install

Helm List

Helm Upgrade

Helm Show

Helm Uninstall

Exam Simulator

Question 1 | Namespaces

Output options

1
2
kubectl get -h
# -o name Print only the resource name and nothing else.

Question 3 | Job

Parallel execution for Jobs

1
2
kubectl explain Job.spec.completions
kubectl explain Job.spec.parallelism

Question 4 | Helm Management

1
2
3
4
5
6
7
8
9
10
11
12
helm list --namespace [NAMESPACE]
# -a, --all
# show all releases without any filter applied
helm uninstall [RELEASE_NAME] --namespace [NAMESPACE]
# upgrade
helm repo list
helm repo update
helm search repo [keyword]
helm upgrade [RELEASE] [CHART] --namespace [NAMESPACE]
# install
helm show values [CHART]
helm install [NAME] [CHART] --set replicaCount=[n] --namespace [NAMESPACE]

Question 5 | ServiceAccount, Secret

1
2
3
4
# base64 encoded token
kubectl get secrets [NAME] -o yaml
# base64 decoded token
kubectl describe secrets [NAME]

Question 11 | Working with Containers

1
2
3
4
5
6
7
8
9
docker build -t NAME[:TAG] -t NAME[:TAG] .
docker push NAME[:TAG]

# podman
podman build -t NAME[:TAG]
podman push NAME[:TAG]
podman run -d --name NAME IMAGE
podman ps
podman logs CONTAINER

Question 13 | Storage, StorageClass, PVC

Storage Classes

Dynamic Volume Provisioning

Question 19 | Service ClusterIP to NodePort

Type NodePort

Question 20 | NetworkPolicy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: <name>
namespace: <namespace>
spec:
podSelector:
matchLabels:
<key>: <value>
policyTypes:
- Egress
egress:
- to:
- podSelector:
matchLabels:
<key>: <value>
- ports: # 2nd egress rule
- port: <port>
protocol: UDP
- port: <port>
protocol: TCP

Notice that we specify two egress rules in the yaml above. If we specify multiple egress rules then these are connected using a logical OR.

Question 22 | Labels, Annotations

1
kubectl label pods -l "KEY in (KEY_1,KEY_2)" KEY_3=VAL_3 ... KEY_N=VAL_N