CICD, DevOps, DevSecOpsの初めの一歩
CICD, DevOps, DevSecOps、なんか開発と運用に絡む言葉だよね!って人向けに
定義のおさらい -> 経験上の詰まりどころやそこから考えたアプローチをつらつらと書きます。
CICD
CI/CDとは、「Continuous Integration and Continuous Delivery/Deployment」の略であり、日本語では継続的インティグレーション/継続的デリバリー (デプロイメント) と呼ばれています。CI/CD は、アプリケーション開発の各ステージに自動化を導入し、顧客にアプリケーションを迅速かつ頻繁に提供できるようにする手法です。
CI と CD をそれぞれ簡単に説明すると、継続的インテグレーション (CI) とは、コード変更を共有ソースコードリポジトリに自動的かつ頻繁に取り込む手法のことです。継続的デリバリーまたはデプロイメント (CD) は 2 つの部分からなるプロセスで、コード変更の統合、テスト、デリバリーを指します。継続的デリバリーは、本番環境への自動デプロイは行わずその手前までを守備範囲としますが、継続的デプロイメントは、更新内容を本番環境に自動的にリリースします。継続的デリバリーと継続的デプロイメントのどちらを選択するかは、リスク許容度と、開発チームと運用チームの具体的なニーズによって異なります。
この文脈では、資源を結合(INTEGRATE)するところ(MERGE工程)までをCI、そこから本番環境へのデプロイ直前までをCD(Delivery, 資源のNew Verをリリースすること)、本番環境にデプロイするところをCD(Deployment, 資源を環境にデプロイすること)と定義しています。特にリリースとデプロイはほぼ同義で扱う場も多い気がするので、ここでのリリースとデプロイは違う点を意識していただけると良いかと。
理解のイメージはリンク先の画像がとてもわかりやすいです。各社様々な文脈でこれらの語句を利用しているケースが散見されるので、気になる方は探して自身の技術感に合う定義を持つと良いと思います。私はこのRed Hat社のものが好きです。
(以前の上司より、CICDの間に"/"を入れると両プロセス分断されるように見えるからつけない、と言うポリシーを聞いていて、私もかなりそれに納得したので上述ではあえて"/"を入れていません)
DevOps
DevOps は、ソフトウェア開発と IT 運用を組み合わせて、ソフトウェア・ソリューションをより迅速に、より確実に、より安定して提供するための一連のプラクティスです。文化、自動化、プラットフォーム設計、継続的なフィードバックループに基本的な重点を置き、より迅速で高品質なサービス提供とより大きなビジネス価値を実現します。
これもRed Hat社の記事を引用させていただいています。以前、お仕事でご一緒させていただいた方が、良くRed Hat社の提供する情報を教えていただき、非常にわかりやすかったので1次リファレンスとして良く使わせてもらっています。
定義における肝の部分は、プラクティスであること。良く物ありきでDevOpsソリューションだなどと言われますが、あくまで自動化や文化、プラットフォームなどを構成する一要素であり、文化がその下に立っている点を忘れてはいけないと考えています。
私が担当した案件でも、多くはDevOpsを取り入れているが中々うまくいかない、といったケースがあり、その真の原因は利用者・ステークホルダーが文化理解・醸成に目を向けてないパターンが多かった印象です。
"Dev""Ops"というように、この言葉の主眼は開発・運用チームといった人と思っています。その人がDevOpsを知らなければ、どのように振る舞うべきか、どういった考え方を持つべきかがわからず、ツールがあっても利用普及に至らないケースがあり、頓挫につながります。Agileと似たようなものと考えてもありかもです。
DevSecOps
DevSecOps (読み方「デブセックオプス」) は、開発 (development)、セキュリティー(security)、運用 (operation) の略です。DevSecOps は、開発と運用を合わせた DevOps に Security (セキュリティ) を加えた概念であり、組織文化、自動化、およびプラットフォーム設計に対するアプローチのことです。DevSecOps では、セキュリティが IT ライフサイクルのすべてのフェーズに統合され、セキュリティに対する責任は組織全体で共有されます。
開発〜運用までがスムーズだとしても、品質がおざなりなら問題が増えて、共倒れになる可能性があります。もちろんそういうケースばかりではないですが、そういった際に自動化・プラットフォームにSecurity文化を加えることで問題の最小化・品質向上をするイメージです。
セキュリティ・テストツールだと、SonarQube, OwaspZapなどの品質分析ツールがありますが、それをCIの中に組み込み機械的に規定品質以下の物を出さないようにする仕組み・また品質の客観的評価・分析が可能になり、人に依存せずに高品質のものを提供できるようになります。
これも大事なのは文化です。良くある考え方として、開発は作ったものを早く出したい、運用はなるべく問題なく現状維持がしたい、という思考があり、どちらにも品質やセキュリティに対する意識・文化はありません。そこから"Sec"を取り込む場合は、品質の大切さを両面に理解いただいて中に入れる必要があります。(これも、皆にいらないと思われてたら使いませんよね)
と、過去の経験を交えた3語の簡単な説明でした。個人的には課題意識が現場の両面にあり、双方とも互いを尊重して改善する意欲がある場合に、適切な識者が旗を振ることで形骸化せずに成熟した印象でした。皆さんの職場における導入時は、是非、文化 -> メソッド・ツールといった順序でやることをお勧めします。かといって負荷が高い状況でお互いが睨み合っている状況では1チームとかもいっていられないと思うので、その場合は各チームに閉じた自動化で負荷を減らし、互いに余裕が生まれたら徐々に両面を繋いでいく、そんなアプローチでも良いのかなと思います。
p.s. この点について、非常に親身に教えていただいたDさんに感謝したいと思います。この場を借りて、ありがとうございます。
Part13. Differences between "Process" and "Thread"
This series is just for my knowledge check of Computer Science...
First, I searched the definition of each items in wiki.
Process
In computer, a process is the isntance of a computer program that is being executed by one or many threads.
Thread
In computer science, a thread of execution is the smallest sequence of programmed instructions that can be managed independently by a scheduler, which is typically a part of the operating system. In many cases, a thread is a component of a process.
From definitions, you can understand that a process contains some threads, you can imagine using the image in the Thread's wiki.
Key differences are...
Process
・An independent execution unit recognized by the OS
・Has its own separate address space
・If one procees terminate, it doesn't affect others
・Inter-Process Communication (IPC) is required ot share data
Thread
・A lightweight execution unit within a process
・Shares the same address space with other threads in the process
・Thread can easily share data
・If one thread crashes, it can affect other threads in the same process
|
Process |
Thread |
|
|
Execution unit |
Independent program |
Task within a process |
|
Memory space |
Separate |
Shared |
|
Communication |
Needs IPC |
Shared variables |
|
Failure impact |
No impact on others |
Can affect other threads |
|
Overhead |
Higher (heavyweight) |
Lower (light weight and faster) |
Part12. What is "Union-Find"???
This series is just for my knowledge check of Computer Science...
What is the "Union-Find (Dijoint Set Union / DSU)"? From ChatGPT4o...
Union-Find, also called Disjoint Set Union(DSU), is a dat structure that efficiently manages a collection of disjoint sets.
It supports two key operations:
1. Find(x): Determine which set element x belongs to (by returning its representative or "root").
2.Union(x,y): Merge the sets that contain elements x and y.
Typical use case:
・Detecting connected components in undirected graphs
・Cycle detection in graphs (e.g., Kruskal's algorithm for Minumum Spanning Tree)
・Grouping objescts into disjoint sets efficiently
How it works?
・Each set is represented as a tree.
・ parent[x] points to the parent of element x.
If x is the root of its set, then parent[x] == x.
You can use this approach in the cases: Network connection validation, Company merger etc...
Sample Implementation:
class UnionFind:
def __init__(selc, n):
self.parent = [i for i in range(n)]
self.rank = [0] * n
def find(self, x):
if self.parent[x] != x:
self.parent[x] = self.find(self.parent[x])
return self.parent[x]
def union(self, x, y):
xr = self.find(x)
yr = self.find(y)
if xr == yr:
return
if self.rank[xr] < self.rank[yr]:
self.parent[xr] = yr
else:
self.parent[yr] = xr
if self.rank[xr] == self.rank[yr]:
self.rank[xr] += 1
Part12. Basic of "Dynamic Programming"
This series is just for my knowledge check of Computer Science...
What is the "Dynamic Programming"? I asked it to ChatGPT4o...
Dynami Programming (DP) is a technique used to solve problems by breaking them down into smaller overlapping subproblems and reusing the results of these subproblems to avoid redundant computation.
Key characteristics:
・Effective when the problem has overlapping subproblems
・Improve efficiency by storing results (memoization or tabulation)
・Requires optimal substructure (the optimal solution can be build from optimal solutions to subproblems)
Typical examples:
・Fibonacci sequence
・Knapsack problem
・Longest Common Subsequence (LCS)
When I found problems in AtCoder, I unconciously used this approach. But it's a bit difficult. It's somtimes rated as Medium problems in AtCoder and Medium (in my feeling)
Heres are some examples of typical problems...
Fibonacci sequence:
def fib(n, memo={}):
if n <= 1:
return n
if n not in memo:
memo[n] = fib(n-1, memo) + fib(n-2, memo)
return memo[n]
### It's like a recursion...
Knapsack problem:
def knapsack(W, wt, val, n):
dp = [[0] * (W + 1) for _ in range(n + 1)]
for i in range(n + 1):
for w in range(W + 1):
if i == 0 or w == 0:
dp[i][w] = 0
elif wt[i-1] <= w:
dp[i][w] = max(val[i-1] + dp[i-1][w - wt[i-1]], dp[i-1][w])
else:
dp[i][w] = dp[i-1][w]
return dp[n][W]
def lcs(X, Y):
m, n = len(X), len(Y)
dp = [[0] * (n + 1) for _ in range(m + 1)]
for i in range(m + 1):
for j in range(n + 1):
if i == 0 or j == 0:
dp[i][j] = 0
elif X[i-1] == Y[j-1]:
dp[i][j] = 1 + dp[i-1][j-1]
else:
dp[i][j] = max(dp[i-1][j], dp[i][j-1])
return dp[m][n]
There is no single way to solve problems with dynamic programming. The approathc depends on the problem, and you have to carefully design the solution using DP techniques.
Part11.Basic of "Recursion"
This series is just for my knowledge check of Computer Science...
What is the "Merge Sort"?
Recursion occurs when the definition of a concept or process depends on a simpler or previous version of itself. The most common application of recursion is in mathematics and computer sciendce, where a function being defined is applied within its own definition. While this apparentle defines an infinite number of instances, it is often done in such a way that no infinite loop or infinite chain of references can occur.
I've implemented some recursive functions for some problems using tree structures. These answers records 0 ms, 100% beats on the LeetCode.
Binary Tree Preorder Traversal - LeetCode
def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
if not root:
return []
r = [root.val]
r.extend(self.preorderTraversal(root.left))
r.extend(self.preorderTraversal(root.right))
return r
def isSameTree(self, p: Optional[TreeNode], q: Optional[TreeNode]) -> bool:
if p is None and q is None:
return True
if p is None or q is None:
return False
if p.val != q.val:
return False
return self.isSameTree(p.left, q.left) and self.isSameTree(p.right, q.right)
When appying recursion, you have to carefully design your functions because as the wikipedia mentioned, recursive approach sometimes causes the infinite loop or chain.
Part10. Basic of "Merge Sort"
This series is just for my knowledge check of Computer Science...
What is the "Merge Sort"?
In computer science, merge sort is an efficient, and comparison-based sorting algorithm. Most implementations of merge sort are stable, which means that the relative order of equal elements is the same between the input and output.
The image and description on wikipedia is very concise and accurate. I strongly recommend the contents on wikipedia.
Algorithm:
1. Divide the unsorted list into n sub-lists, each containing one element (a list of one element is considered sorted).
2. Repeatedly merge sublists to produce new sorted sublists until there is only one sublist remaining. This will be the sorted list.
※ I can't imagine the real example of this algorithm, so if you have real example, please comment on this article!
Sample Implementation:
def merge_sort(arr):
if len(arr) <= 1:
return arr
mid = len(arr) // 2
left = merge_sort(arr[:mid]
right = merge_sort(arr[mid:])
return merge(left, right)
def merge(left, right):
result = []
i = j = 0
while i < len(left) and k < len(right):
if left[i] <= right[j]:
result.append(left[i])
i+=1
else:
result.append(right[i])
j+=1
result.extend([left[i:])
result.extend([right[j:])
return result
Part9. Basic of "Insertion Sort"
This series is just for my knowledge check of Computer Science...
What is the "Insertion Sort"?
Insertion sort is a simple sorting algorithm that builds the final sorted array (or list) one item at a time by comparisons. It is much less efficient on large lists than more advanced algorithms such as quicksort, heapsort, or merge sort. However, insertion sort provides several advantages:
The imege on the wikipedia is the most imageable. First, start from the left and move right through the list. For each element, insert into the correct position among the elements to its left (the "sorted part"). And repeat these processes until all elements are sorted. Time complexity is O(n^2) (Worst case). But there are faster sort algorithms than this.
Sample implementation:
def insertion_sort(arr):
for i in range(1, len(arr):
key = arr[i]
j = i-1
while j >= 0 and arr[j] > key:
arr[j+1] = arr[j]
j -= 1
arr[j + 1] = key