<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>mosaos</title>
    <subtitle>mosaos portfolio and blog</subtitle>
    <link href="https://mosaos.github.io/atom.xml" rel="self" type="application/atom+xml"/>
    <link href="https://mosaos.github.io/"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-09-28T00:00:00+00:00</updated>
    <id>https://mosaos.github.io/atom.xml</id>
    <entry xml:lang="en">
        <title>Modifying a Speaker Protection Board</title>
        <published>2026-09-28T00:00:00+00:00</published>
        <updated>2026-09-28T00:00:00+00:00</updated>
        <author>
          <name>Unknown</name>
        </author>
        <link rel="alternate" href="https://mosaos.github.io/blog/customize-sp-protection-board/" type="text/html"/>
        <id>https://mosaos.github.io/blog/customize-sp-protection-board/</id>
        
        <content type="html">&lt;h2 id=&quot;speaker-protection-board&quot;&gt;Speaker Protection Board&lt;&#x2F;h2&gt;
&lt;p&gt;While browsing AliExpress, I found something called an audio speaker protection board, so I decided to give it a try.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;mosaos.github.io&#x2F;blog&#x2F;customize-sp-protection-board&#x2F;.&#x2F;sp-protection-board-01.webp&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This one is rated for AC 12-16V. It is sold as a kit rather than assembled (although assembled versions are also available).&lt;br &#x2F;&gt;
There were quite a few similar products, but I chose one with a reasonable number of reviews (see &lt;a href=&quot;https:&#x2F;&#x2F;mosaos.github.io&#x2F;blog&#x2F;customize-sp-protection-board&#x2F;.&#x2F;#aliexpress&quot;&gt;Aliexpress Link&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;I bought two, and both arrived safely.&lt;&#x2F;p&gt;
&lt;p&gt;I have a DIY digital amplifier, so I was thinking about incorporating this into it. However, as mentioned above, this board is designed for AC (alternating current) 12V-16V.&lt;br &#x2F;&gt;
I expected that it would not work as-is, so I bought it with the intention of modifying it.&lt;&#x2F;p&gt;
&lt;p&gt;Here is the board.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;mosaos.github.io&#x2F;blog&#x2F;customize-sp-protection-board&#x2F;.&#x2F;pcb.webp&quot; alt=&quot;PCB&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;From the board and the photos of the completed product, I was able to determine the following first.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;There is a &lt;strong&gt;bridge rectifier&lt;&#x2F;strong&gt; to convert the AC input to DC (marked &lt;code&gt;A1&lt;&#x2F;code&gt; on the board).&lt;br &#x2F;&gt;
Digital amplifiers and similar devices use DC (direct current), so this is not necessary.&lt;&#x2F;li&gt;
&lt;li&gt;There is a &lt;strong&gt;three-terminal regulator&lt;&#x2F;strong&gt; after the bridge rectifier (marked &lt;code&gt;L7812CV&lt;&#x2F;code&gt; on the board).&lt;br &#x2F;&gt;
This converts the rectified voltage from AC 12-16V to 12V DC. A digital amplifier that operates at 12V DC or less does not need this either.&lt;br &#x2F;&gt;
※ Since &lt;code&gt;ACV × √2&lt;&#x2F;code&gt; is the theoretical value, AC 12V becomes approximately DC 17V. Due to the voltage drop across the diodes, the actual voltage is around 15V.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Therefore, I expected that the board should work with a DC-powered amplifier if these parts were bypassed.&lt;&#x2F;p&gt;
&lt;p&gt;* It is also possible to input DC 12V before the bridge rectifier. However, due to the voltage drop caused by the bridge rectifier and three-terminal regulator, the voltage supplied to the circuit itself would be around 9V, which would likely cause the relay to operate unreliably.&lt;&#x2F;p&gt;
&lt;p&gt;I also decided to convert it to DC 5V so that I could use it with the PAM8406 I had on hand. This required the following modifications as well.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Replace the relay&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
Since the voltage supplied to the circuit will change from DC 12V to DC 5V, the relay needs to be replaced. The board comes with an &lt;code&gt;SRD-12VDC-SL-C&lt;&#x2F;code&gt;, so I replaced it with an &lt;code&gt;SRD-05VDC-SL-C&lt;&#x2F;code&gt;.&lt;br &#x2F;&gt;
I bought &lt;code&gt;SRD-05VDC-SL-C 5PIN, 5PCS&lt;&#x2F;code&gt; (see &lt;a href=&quot;https:&#x2F;&#x2F;mosaos.github.io&#x2F;blog&#x2F;customize-sp-protection-board&#x2F;.&#x2F;#aliexpress&quot;&gt;Aliexpress Link&lt;&#x2F;a&gt;).&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Change the resistor value so that the 5V relay can operate&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
The circuit will be supplied with DC 5V instead of DC 12V. As can be seen from the product page for the relay above, the required current (coil current) is as follows:
&lt;ul&gt;
&lt;li&gt;5V: 72 mA&lt;&#x2F;li&gt;
&lt;li&gt;12V: 30 mA&lt;br &#x2F;&gt;
Since the voltage also drops from 12V to 5V, the relay would most likely not respond at all if the resistor were left unchanged.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;modification&quot;&gt;Modification&lt;&#x2F;h2&gt;
&lt;p&gt;First, here is a photo of the board after applying the modifications described above.&lt;&#x2F;p&gt;
&lt;img src=&quot;customized-01.webp&quot; width=&quot;50%&quot; alt=&quot;Modification 1&quot;&gt;
&lt;p&gt;At this point, there are three modification areas (Section 1 - Section 3).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;section-1&quot;&gt;Section 1&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;Do not install either &lt;code&gt;A1&lt;&#x2F;code&gt; or &lt;code&gt;L7812CV&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;The terminal that was originally connected to the &lt;code&gt;AC&lt;&#x2F;code&gt; section was instead connected to the output side of &lt;code&gt;A1&lt;&#x2F;code&gt; (where &lt;code&gt;+&lt;&#x2F;code&gt; and &lt;code&gt;-&lt;&#x2F;code&gt; are printed).&lt;&#x2F;li&gt;
&lt;li&gt;As you can see from the PCB traces, this alone would not supply &lt;code&gt;+&lt;&#x2F;code&gt; to the circuit, so short both ends of &lt;code&gt;L7812CV&lt;&#x2F;code&gt; with a jumper wire. Be careful not to touch the center pad and cause a short circuit. I used an insulated wire rather than a cut-off component lead.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;With this modification, the DC supplied to the terminal goes directly into the circuit.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;section-2&quot;&gt;Section 2&lt;&#x2F;h3&gt;
&lt;p&gt;This is the part mentioned above: &lt;strong&gt;changing the resistor value so that the 5V relay can operate&lt;&#x2F;strong&gt;. The board originally has a &lt;code&gt;100K&lt;&#x2F;code&gt; resistor here. When I asked an AI about this, it told me that &amp;quot;shorting this part will make the relay respond,&amp;quot; but &lt;strong&gt;&lt;span style=color:red&gt;that will kill the transistor&lt;&#x2F;span&gt;&lt;&#x2F;strong&gt;, so don&#x27;t do that lol.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;section-3&quot;&gt;Section 3&lt;&#x2F;h3&gt;
&lt;p&gt;Replace the relay from &lt;code&gt;SRD-12VDC-SL-C&lt;&#x2F;code&gt; with &lt;code&gt;SRD-05VDC-SL-C&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;section-4&quot;&gt;Section 4&lt;&#x2F;h3&gt;
&lt;p&gt;I had not noticed this at this point. (Described later.)&lt;&#x2F;p&gt;
&lt;h2 id=&quot;testing&quot;&gt;Testing&lt;&#x2F;h2&gt;
&lt;p&gt;I have a modified USB cable made from a USB cable I bought at a 100-yen shop (one that had already suffered a broken wire or something), so I connected it to the terminal and then to a mobile battery for testing.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;mosaos.github.io&#x2F;blog&#x2F;customize-sp-protection-board&#x2F;.&#x2F;usb-cable.webp&quot; alt=&quot;USB cable&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;At this point, I tried the following for Section 2.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;First, I tested it with 10K.&lt;br &#x2F;&gt;
The relay operated with a &amp;quot;click&amp;quot; in less than one second.&lt;&#x2F;li&gt;
&lt;li&gt;I changed it to 47K.&lt;br &#x2F;&gt;
It sometimes operated, but it was unstable. The delay increased to a little over two seconds.&lt;&#x2F;li&gt;
&lt;li&gt;I wanted to use 33K, but I did not have one, so I connected two 68K resistors in parallel (= 34K).&lt;br &#x2F;&gt;
The delay was a little over one second, and the operation was stable, so I settled on this.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;I confirmed that the relay responds with a DC 5V input.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;connecting-the-amplifier&quot;&gt;Connecting the amplifier&lt;&#x2F;h3&gt;
&lt;p&gt;I connected the PAM8406 and checked whether it would actually work.&lt;&#x2F;p&gt;
&lt;p&gt;Looking at the traces on the back of this board makes it immediately obvious, but &lt;strong&gt;the speaker GND is shared&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Many digital amplifiers, including the PAM8406, use a BTL connection. Unlike a single-ended amplifier, L-&#x2F;R- (which have a voltage in the opposite phase to the + output) are not GND. &lt;strong&gt;&lt;span style=color:red&gt;They must not be shorted together.&lt;&#x2F;span&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Connecting the negative outputs from the amplifier (L-&#x2F;R-) to this board can, in the worst case, destroy the amplifier, so absolutely do not connect them.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;So what should you do?&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Connect L+&#x2F;R+ to L&#x2F;R on this board (the side that is not shorted together on the back of the board).&lt;&#x2F;li&gt;
&lt;li&gt;Connect L-&#x2F;R- directly to the speakers without passing them through this board.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I connected the PAM8406 while paying attention to the short-circuit issue described above, but, as it turned out, it did not work at all lol.&lt;&#x2F;p&gt;
&lt;p&gt;In fact, this board is not just a delay relay. As the &amp;quot;DC protection&amp;quot; in the product description indicates (something I noticed again later lol), it also detects DC flowing to the speakers and prevents the relay from operating when DC leakage is detected.&lt;&#x2F;p&gt;
&lt;p&gt;For such an inexpensive circuit, it was actually quite well designed.&lt;&#x2F;p&gt;
&lt;p&gt;The PCB traces already show that it is not designed for BTL operation = it is intended for single-ended amplifiers. In that case, the DC protection does not cause any problems. With BTL, however, voltage is applied to both the + and - outputs, so the DC protection was triggered and the relay would not turn on. That was the reason it did not work.&lt;&#x2F;p&gt;
&lt;p&gt;* With VDD = 5V, both OUT+ and OUT- have approximately 2.5V (slightly less) of DC voltage even when there is no signal.&lt;&#x2F;p&gt;
&lt;p&gt;One possible approach would be to change the resistor connected to the DC protection circuit (Section 4) so that the DC protection does not activate even when the PAM8406 produces 2.5V. However, that seemed like a hassle (and, after all, I bought this board because I wanted a delay relay to prevent pop noise), so I dealt with it by removing the resistor in Section 4.&lt;&#x2F;p&gt;
&lt;p&gt;The DC protection will no longer work, but if preventing pop noise at startup is sufficient for your requirements, this modification does the job.&lt;&#x2F;p&gt;
&lt;p&gt;In the end, the amplifier became something like this:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;PAM8406&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Bluetooth (v5) support&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
Compatible boards are available cheaply.&lt;&#x2F;li&gt;
&lt;li&gt;The &lt;strong&gt;speaker protection board&lt;&#x2F;strong&gt; used in this modification&lt;br &#x2F;&gt;
All of the above are supplied with 5V from a USB-C connector (split in parallel).&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Two audio inputs&lt;&#x2F;strong&gt;: a 3.5mm stereo phone jack and Bluetooth&lt;br &#x2F;&gt;
They are switched using a 2-circuit, 2-position toggle switch. (The GND of the audio input does not need to be switched and can be shared.)&lt;&#x2F;li&gt;
&lt;li&gt;The speakers are also connected using a 3.5mm phone jack.&lt;br &#x2F;&gt;
I used a Takachi YM-10 (YM10-3-7) aluminum enclosure to keep the unit compact, so a speaker terminal would have been difficult to fit. I am also using the YM series in a somewhat unusual way, rather than its typical use with the silver side as the front.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Originally, my child had an AG03, but there was no way to drive the passive speakers I had on hand, so I made this amplifier.&lt;br &#x2F;&gt;
Bluetooth was not a requirement, but considering that it might also be used as a standalone amplifier, being able to play audio from a smartphone or similar device via Bluetooth makes it more versatile.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Here is a photo. I used YAMORI GRIP (extra-strong double-sided gel tape), which can be bought at 100-yen shops and elsewhere, to secure the boards. I protected the terminals with masking tape so that they would not touch the case.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;* YAMORI GRIP itself is quite thick (2 mm), so that alone is probably enough in many cases. However, when using a metal case, I think it is better to take some precautions just in case.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;mosaos.github.io&#x2F;blog&#x2F;customize-sp-protection-board&#x2F;.&#x2F;pam8406-amp.webp&quot; alt=&quot;PAM8406 amplifier&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;other-digital-amplifiers&quot;&gt;Other Digital Amplifiers&lt;&#x2F;h2&gt;
&lt;p&gt;I also have a TA2020 (based on an NFJ board), so I will probably make a version that keeps the DC 12V supply at some point.&lt;&#x2F;p&gt;
&lt;p&gt;In that case, only Section 1 and Section 4 need to be modified.&lt;&#x2F;p&gt;
&lt;p&gt;There are also other digital amplifiers such as the PAM8403, which is said to have more noticeable pop noise than the PAM8406. Therefore, if you want to reduce pop noise on a digital amplifier at relatively low cost, the modifications described in this article may also be useful.&lt;&#x2F;p&gt;
&lt;p&gt;Since this involves modifying electronic hardware, &lt;strong&gt;please try it at your own risk&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Zola daisyUI blog</title>
        <published>2026-09-25T00:00:00+00:00</published>
        <updated>2026-09-25T00:00:00+00:00</updated>
        <author>
          <name>Unknown</name>
        </author>
        <link rel="alternate" href="https://mosaos.github.io/blog/zola-daisyui-blog/" type="text/html"/>
        <id>https://mosaos.github.io/blog/zola-daisyui-blog/</id>
        
        <content type="html">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;I created a blog template using Zola + daisyUI, so I am writing this article as a reminder for myself as well.&lt;&#x2F;p&gt;
&lt;p&gt;This article describes why I created it, the setup procedure, and so on.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;why-did-i-create-it&quot;&gt;Why did I create it?&lt;&#x2F;h2&gt;
&lt;p&gt;I had been thinking about sharing personal information through GitHub Pages for some time, but I finally got around to building the application.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mosaos&#x2F;zola-daisyui-blog&quot;&gt;mosaos&#x2F;zola-daisyui-blog&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;* An actual example can be found here.&lt;&#x2F;p&gt;
&lt;p&gt;At first, I tried implementing a simple version with React&#x2F;TypeScript (I had already made it possible to display Markdown), and I also tried using Astro based on AI advice. In the end, I settled on the following technology stack.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Zola&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
An SSG (Static Site Generator) written in Rust&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;daisyUI&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
A component library for Tailwind CSS&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;GitHub Pages&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
A requirement from the beginning&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The reason I stopped using Node.js was simply that I did not want to end up in a maintenance hell.&lt;&#x2F;p&gt;
&lt;p&gt;I work on React projects in my professional work as well, but Node.js-based projects tend to have:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Many related packages&lt;&#x2F;li&gt;
&lt;li&gt;A lot of security (vulnerability) fixes&lt;&#x2F;li&gt;
&lt;li&gt;Many breaking changes&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The fact that I am particularly bothered by breaking changes may also be because Java (such as Spring Boot) is my strongest language. Having to perform maintenance even though the actual application itself has not changed is one thing when doing it for work, but it is a hassle for a personal information-sharing site.&lt;&#x2F;p&gt;
&lt;p&gt;For these reasons, I ended up with the configuration above.&lt;&#x2F;p&gt;
&lt;p&gt;Some people may say that daisyUI also requires Node.js, but if you use something like the &lt;code&gt;full.css&lt;&#x2F;code&gt; published via CDN, you can use Tailwind &#x2F; daisyUI without a Tailwind&#x2F;daisyUI build process. (It includes everything, though.)&lt;&#x2F;p&gt;
&lt;p&gt;There may also be arguments about optimization, but avoiding maintenance hell is the most important requirement for me, so using resources from a CDN is perfectly fine.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;features&quot;&gt;Features&lt;&#x2F;h2&gt;
&lt;p&gt;This is the template I created. See &lt;code&gt;README.md&lt;&#x2F;code&gt; for details, but it has the following features.&lt;br &#x2F;&gt;
&lt;em&gt;Most of these are essentially characteristics of Zola&#x2F;daisyUI and so on.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Responsive Design&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
A simple and easy-to-use layout that also supports mobile devices, powered by daisyUI and Tailwind CSS.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Markdown-based&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
Blog posts and portfolio works can be easily created using Markdown. Articles can also display a Table of Contents (TOC).&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Multilingual Support&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
A multilingual switcher is included by default. It can be extended to any number of languages as needed.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Static Site Generation (SSG)&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
Fast and secure, with no need for server-side runtimes such as Node.js.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Dev Containers Support&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
The development environment can be set up quickly, reducing the effort required for environment setup.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Tag Support&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
Content can be organized and categorized using tags.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Image Carousel &#x2F; Slideshow&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
A carousel is included for displaying multiple photos or images, such as portfolio works.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;development-environment&quot;&gt;Development Environment&lt;&#x2F;h2&gt;
&lt;p&gt;I have tested it with the following environment.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Windows 11&lt;&#x2F;li&gt;
&lt;li&gt;WSL2 (Ubuntu)&lt;&#x2F;li&gt;
&lt;li&gt;docker-ce&lt;br &#x2F;&gt;
Used when using Dev Containers. This is not Docker Desktop, so it can also be used in companies that do not have a Docker Desktop license.&lt;&#x2F;li&gt;
&lt;li&gt;VS Code&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;setup&quot;&gt;Setup&lt;&#x2F;h2&gt;
&lt;p&gt;The application part is registered on GitHub as a template project. The recommended procedure is as follows.&lt;&#x2F;p&gt;
&lt;p&gt;Since symbolic links are used to check the site locally, WSL2 is recommended (when using Windows).&lt;br &#x2F;&gt;
&lt;em&gt;I don&#x27;t know about Mac.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;creating-the-repositories&quot;&gt;Creating the Repositories&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;Access &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mosaos&#x2F;zola-daisyui-blog&quot;&gt;mosaos&#x2F;zola-daisyui-blog&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Click &lt;code&gt;Use this template&lt;&#x2F;code&gt; &amp;gt; &lt;code&gt;Create a new repository&lt;&#x2F;code&gt; and create it as your own repository (such as &lt;code&gt;my-portfolio&lt;&#x2F;code&gt;). &lt;code&gt;Private&lt;&#x2F;code&gt; is also fine.&lt;&#x2F;li&gt;
&lt;li&gt;Create a separate repository for the content, such as &lt;code&gt;my-portfolio-content&lt;&#x2F;code&gt;. &lt;code&gt;Private&lt;&#x2F;code&gt; is fine.&lt;br &#x2F;&gt;
This separates the application and content so that the application part can be updated more easily if it is updated in the future. If you do not want the extra hassle, you can also keep everything in &lt;code&gt;my-portfolio&lt;&#x2F;code&gt; from step 2 without separating the content.&lt;&#x2F;li&gt;
&lt;li&gt;Create a repository for GitHub Pages (&lt;code&gt;Public&lt;&#x2F;code&gt;). If you want to publish the site directly under the domain, use &lt;code&gt;username.github.io&lt;&#x2F;code&gt; as the repository name.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;check-the-site-locally-first&quot;&gt;Check the Site Locally First&lt;&#x2F;h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;If you did not separate the content repository, you do not need to replace it with a symbolic link.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h4 id=&quot;without-dev-containers&quot;&gt;Without Dev Containers&lt;&#x2F;h4&gt;
&lt;p&gt;Create a symbolic link from the application-side &lt;code&gt;content&lt;&#x2F;code&gt; directory to the content repository.&lt;&#x2F;p&gt;
&lt;p&gt;Delete the &lt;code&gt;content&lt;&#x2F;code&gt; directory on the application side (&lt;code&gt;my-portfolio&lt;&#x2F;code&gt;):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;cd&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;path&#x2F;to&#x2F;my-portfolio
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rm -rf&lt;&#x2F;span&gt;&lt;span&gt; content
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Create a symbolic link to the content repository (&lt;code&gt;my-portfolio-content&lt;&#x2F;code&gt;).&lt;br &#x2F;&gt;
&lt;em&gt;The following assumes that &lt;code&gt;my-portfolio&lt;&#x2F;code&gt; and &lt;code&gt;my-portfolio-content&lt;&#x2F;code&gt; are in the same directory.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ln -s&lt;&#x2F;span&gt;&lt;span&gt; ..&#x2F;my-portfolio-content content
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h4 id=&quot;with-dev-containers&quot;&gt;With Dev Containers&lt;&#x2F;h4&gt;
&lt;p&gt;Symbolic links do not work here, so mount the directory instead.&lt;&#x2F;p&gt;
&lt;p&gt;Do not delete the &lt;code&gt;content&lt;&#x2F;code&gt; directory in &lt;code&gt;my-portfolio&lt;&#x2F;code&gt;; just remove its contents.&lt;&#x2F;p&gt;
&lt;p&gt;Add the following &lt;code&gt;mounts&lt;&#x2F;code&gt; definition to &lt;code&gt;devcontainer.json&lt;&#x2F;code&gt; in &lt;code&gt;my-portfolio&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;json&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-json &quot;&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;forwardPorts&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;: [
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1111
&lt;&#x2F;span&gt;&lt;span&gt;    ],
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; Bind-mount the content repository on the host to the Zola content directory in the container
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;mounts&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;: [
&lt;&#x2F;span&gt;&lt;span&gt;        {
&lt;&#x2F;span&gt;&lt;span&gt;            &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;source&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;${localWorkspaceFolder}&#x2F;..&#x2F;my-portfolio-content&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;            &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;target&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;${containerWorkspaceFolder}&#x2F;content&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;            &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;type&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;bind&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;    ]
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; &amp;quot;remoteUser&amp;quot;: &amp;quot;root&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After configuring this, run &lt;code&gt;Rebuild Container&lt;&#x2F;code&gt;. If the contents of &lt;code&gt;content&lt;&#x2F;code&gt; are visible (linked) from the Dev Container, the setup was successful.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;check-the-site&quot;&gt;Check the Site&lt;&#x2F;h4&gt;
&lt;p&gt;Check the site locally.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;cd&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;path&#x2F;to&#x2F;my-portfolio
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If you are using a Dev Container, open VS Code and check from the Dev Container terminal.&lt;&#x2F;p&gt;
&lt;p&gt;Otherwise, you can check it using Zola installed on WSL2 (Ubuntu).&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;code&lt;&#x2F;span&gt;&lt;span&gt; .
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;zola&lt;&#x2F;span&gt;&lt;span&gt; serve&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --interface&lt;&#x2F;span&gt;&lt;span&gt; 0.0.0.0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --port&lt;&#x2F;span&gt;&lt;span&gt; 1111&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --base-url&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In VS Code, a dialog saying &lt;code&gt;Your application running on port 1111 is available. See all forwarded ports&lt;&#x2F;code&gt; will appear. Click &lt;code&gt;Open in Browser&lt;&#x2F;code&gt;, and if the site is displayed, everything is OK.&lt;&#x2F;p&gt;
&lt;p&gt;If you are not using VS Code, open http:&#x2F;&#x2F;localhost:1111&#x2F; and check that the site is displayed.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;adjust-gitignore&quot;&gt;Adjust &lt;code&gt;.gitignore&lt;&#x2F;code&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Once you have confirmed that it works, exclude the contents of the &lt;code&gt;content&lt;&#x2F;code&gt; directory on the &lt;code&gt;my-portfolio&lt;&#x2F;code&gt; side so that the files in &lt;code&gt;my-portfolio-content&lt;&#x2F;code&gt; are not managed in multiple places. Add the following:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;.gitignore&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-.gitignore &quot;&gt;&lt;code class=&quot;language-.gitignore&quot; data-lang=&quot;.gitignore&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;content&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;**
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You may also want to run the following in &lt;code&gt;my-portfolio&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; rm&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --cached -r&lt;&#x2F;span&gt;&lt;span&gt; content
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;At this point, the local development&#x2F;checking environment is ready.&lt;&#x2F;p&gt;
&lt;p&gt;You can now add content or customize the application part as needed.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;prepare-a-pat-github-personal-access-token&quot;&gt;Prepare a PAT (GitHub Personal Access Token)&lt;&#x2F;h3&gt;
&lt;p&gt;From here, the setup is for publishing the site to GitHub Pages using GitHub Actions.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;This is not necessary if you plan to generate the SSG site manually using Zola locally&#x2F;in a Dev Container and publish the generated pages yourself.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;my-portfolio&lt;&#x2F;code&gt; needs access to the separate private repository (&lt;code&gt;my-portfolio-content&lt;&#x2F;code&gt;) and the public repository (&lt;code&gt;username.github.io&lt;&#x2F;code&gt;). Prepare a PAT using the following procedure.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Open &lt;code&gt;Tokens (classic)&lt;&#x2F;code&gt; from &lt;code&gt;Settings&lt;&#x2F;code&gt; &amp;gt; &lt;code&gt;Developer settings&lt;&#x2F;code&gt; &amp;gt; &lt;code&gt;Personal access tokens&lt;&#x2F;code&gt;, using your account icon on the upper right.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;code&gt;Generate new token (classic)&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Enter a description in &lt;code&gt;Note&lt;&#x2F;code&gt; (such as &lt;code&gt;portfolio deploy token&lt;&#x2F;code&gt;) and set the expiration date.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Recommended:&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
From a security perspective, &lt;strong&gt;&lt;code&gt;30 days&lt;&#x2F;code&gt; or &lt;code&gt;60 days&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; (regular renewal is required)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Compromise for personal use:&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
If you want to reduce the effort of renewing it, &lt;strong&gt;&lt;code&gt;90 days&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; (a reminder email will be sent shortly before expiration)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;em&gt;&lt;code&gt;No expiration&lt;&#x2F;code&gt; is not recommended because the risk is high if the token is leaked.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Under &lt;code&gt;Select scopes&lt;&#x2F;code&gt;, check:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;repo&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;code&gt;Generate token&lt;&#x2F;code&gt; at the bottom of the page and keep the generated token somewhere safe. (&lt;em&gt;It cannot be displayed again once you close the page.&lt;&#x2F;em&gt;)&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;register-the-token-in-github-secrets&quot;&gt;Register the Token in GitHub Secrets&lt;&#x2F;h3&gt;
&lt;p&gt;Register the issued token as a secret in the application-side repository (&lt;code&gt;my-portfolio&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Open your &lt;code&gt;my-portfolio&lt;&#x2F;code&gt; repository page.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Go to &lt;code&gt;Settings&lt;&#x2F;code&gt; &amp;gt; &lt;code&gt;Secrets and variables&lt;&#x2F;code&gt; &amp;gt; &lt;code&gt;Actions&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;code&gt;New repository secret&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Name: &lt;code&gt;GH_PAT&lt;&#x2F;code&gt; (or another easy-to-understand name)&lt;&#x2F;li&gt;
&lt;li&gt;Secret: Paste the PAT string you copied earlier.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;code&gt;Add secret&lt;&#x2F;code&gt; to save it.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;create-the-github-actions-workflow&quot;&gt;Create the GitHub Actions Workflow&lt;&#x2F;h3&gt;
&lt;p&gt;Create a GitHub Actions configuration file in the root of the application-side repository (&lt;code&gt;my-portfolio&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;This configuration is based on the author&#x27;s setup, so change it as appropriate.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h4 id=&quot;github-workflows-deploy-yml&quot;&gt;.github&#x2F;workflows&#x2F;deploy.yml&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;yaml&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-yaml &quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Build and Deploy Zola Site
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;on&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;branches&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;main &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# use master instead if your repository uses master
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;jobs&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;build-and-deploy&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;runs-on&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ubuntu-latest
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;steps&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# 1. Check out the application repository
&lt;&#x2F;span&gt;&lt;span&gt;      - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Checkout my-portfolio
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;uses&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;actions&#x2F;checkout@v4
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# 2. Check out the content repository (Private) directly into the content&#x2F; directory
&lt;&#x2F;span&gt;&lt;span&gt;      - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Checkout my-portfolio-content
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;uses&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;actions&#x2F;checkout@v4
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;with&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;repository&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;mosaos&#x2F;my-portfolio-content &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# username&#x2F;content repository name
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;token&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;${{ secrets.GH_PAT }}
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;path&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;content
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# 3. Install Zola
&lt;&#x2F;span&gt;&lt;span&gt;      - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Setup Zola
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;uses&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;taiki-e&#x2F;install-action@v2
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;with&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;tool&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;zola@0.17.2 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# Match the version used in the development environment
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# 4. Build the site with Zola
&lt;&#x2F;span&gt;&lt;span&gt;      - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Build Zola site
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;run&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;zola build
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# 5. Push the build output (public&#x2F;) to the mosaos.github.io repository
&lt;&#x2F;span&gt;&lt;span&gt;      - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Push to mosaos.github.io
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;env&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;GH_TOKEN&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;${{ secrets.GH_PAT }}
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;run&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;|
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;          git config --global user.name &amp;quot;GitHub Actions Bot&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;          git config --global user.email &amp;quot;actions@github.com&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;          # Move to the public directory containing the build output
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;          cd public
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;          # Initialize it as a Git repository and push
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;          git init
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;          git checkout -b main
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;          git remote add origin https:&#x2F;&#x2F;x-access-token:${{ secrets.GH_PAT }}@github.com&#x2F;mosaos&#x2F;mosaos.github.io.git
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;          git add -A
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;          git commit -m &amp;quot;Deploy from my-portfolio CI&#x2F;CD at $(date)&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;          git push -f origin main
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After creating the configuration file, commit and push it.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Before committing&#x2F;pushing, change &lt;code&gt;base_url&lt;&#x2F;code&gt; in &lt;code&gt;config.yml&lt;&#x2F;code&gt; to the URL of your own GitHub Pages site.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;If the Action runs successfully, everything is OK. At this point, if &lt;code&gt;content&lt;&#x2F;code&gt; has not been registered yet, the Action will fail, but after registering &lt;code&gt;content&lt;&#x2F;code&gt;, rerun it and make sure it completes successfully.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;github-pages-settings-on-the-deployment-destination-username-github-io&quot;&gt;GitHub Pages Settings on the Deployment Destination (&lt;code&gt;username.github.io&lt;&#x2F;code&gt;)&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;Open &lt;code&gt;Settings&lt;&#x2F;code&gt; &amp;gt; &lt;code&gt;Pages&lt;&#x2F;code&gt; in the &lt;code&gt;username.github.io&lt;&#x2F;code&gt; repository.&lt;&#x2F;li&gt;
&lt;li&gt;Configure &lt;code&gt;Build and deployment&lt;&#x2F;code&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Source&lt;&#x2F;code&gt;: Select &lt;code&gt;Deploy from a branch&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Branch&lt;&#x2F;code&gt;: Select &lt;code&gt;main&lt;&#x2F;code&gt; (or &lt;code&gt;master&lt;&#x2F;code&gt;) and &lt;code&gt;&#x2F;&lt;&#x2F;code&gt; (root) as the folder, then click &lt;code&gt;Save&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;triggering-a-build-when-content-is-updated&quot;&gt;Triggering a Build When &lt;code&gt;content&lt;&#x2F;code&gt; Is Updated&lt;&#x2F;h2&gt;
&lt;p&gt;With the configuration above, an update to &lt;code&gt;my-portfolio&lt;&#x2F;code&gt; (a push to &lt;code&gt;main&lt;&#x2F;code&gt;) triggers Actions.&lt;&#x2F;p&gt;
&lt;p&gt;Normally, it is more convenient for the site to be updated when &lt;code&gt;content&lt;&#x2F;code&gt; is updated.&lt;&#x2F;p&gt;
&lt;p&gt;In this case, add the following configuration to both the application-side (&lt;code&gt;my-portfolio&lt;&#x2F;code&gt;) and content-side (&lt;code&gt;my-portfolio-content&lt;&#x2F;code&gt;) repositories.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;application-side-my-portfolio&quot;&gt;Application Side (&lt;code&gt;my-portfolio&lt;&#x2F;code&gt;)&lt;&#x2F;h3&gt;
&lt;p&gt;Modify the &lt;code&gt;on:&lt;&#x2F;code&gt; section of &lt;code&gt;.github&#x2F;workflows&#x2F;deploy.yml&lt;&#x2F;code&gt; on the application side so that it can wait for a signal (&lt;code&gt;repository_dispatch&lt;&#x2F;code&gt;) from the content side.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;github-workflows-deploy-yml-1&quot;&gt;.github&#x2F;workflows&#x2F;deploy.yml&lt;&#x2F;h4&gt;
&lt;p&gt;Add the following near the beginning.&lt;&#x2F;p&gt;
&lt;p&gt;Register the &lt;code&gt;GH_PAT&lt;&#x2F;code&gt; secret in the same way as you did for the application-side repository.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-yaml &quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Build and Deploy Zola Site
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;on&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;branches&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;main &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# or master
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# Add a setting to receive events from an external repository (the content repository)
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;repository_dispatch&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;types&lt;&#x2F;span&gt;&lt;span&gt;: [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;content_updated&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;jobs&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;build-and-deploy&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;runs-on&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ubuntu-latest
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;#  ( the rest is omitted )
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;content-side-my-portfolio-content&quot;&gt;Content Side (&lt;code&gt;my-portfolio-content&lt;&#x2F;code&gt;)&lt;&#x2F;h3&gt;
&lt;h3 id=&quot;github-workflows-deploy-yml-2&quot;&gt;.github&#x2F;workflows&#x2F;deploy.yml&lt;&#x2F;h3&gt;
&lt;p&gt;Create a new configuration file.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-yaml &quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Trigger App Build on Content Push
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;on&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;branches&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;main &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# Match the main branch used to manage articles (Markdown)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;jobs&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;trigger_dispatch&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;runs-on&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ubuntu-latest
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;steps&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Repository Dispatch
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;uses&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;peter-evans&#x2F;repository-dispatch@v3
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;with&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;token&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;${{ secrets.GH_PAT }} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# Register the same GH_PAT as a Secret on the content side
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;repository&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;mosaos&#x2F;my-portfolio &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# Target application-side repository
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;event-type&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;content_updated &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# Must exactly match the name configured in types on the application side (be careful with hyphens)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;keeping-up-with-updates-to-zola-daisyui-blog&quot;&gt;Keeping Up with Updates to zola-daisyui-blog&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;register-the-upstream-repository&quot;&gt;Register the Upstream Repository&lt;&#x2F;h3&gt;
&lt;p&gt;A repository created with &lt;code&gt;Use this template&lt;&#x2F;code&gt; is completely independent of the original repository, unlike a Fork.&lt;&#x2F;p&gt;
&lt;p&gt;If you want to keep your repository up to date with changes to the original template repository, set this up first.&lt;&#x2F;p&gt;
&lt;p&gt;Move to the root of the project you created:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;cd&lt;&#x2F;span&gt;&lt;span&gt; my-portfolio
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Add the upstream repository:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; remote add upstream https:&#x2F;&#x2F;github.com&#x2F;mosaos&#x2F;zola-daisyui-blog
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can check whether it was registered correctly with:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; remote&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -v
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;apply-changes-from-the-original-template&quot;&gt;Apply Changes from the Original Template&lt;&#x2F;h3&gt;
&lt;p&gt;First, fetch the changes:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; fetch upstream
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;With a normal merge, Git may consider the histories unrelated, so merge with &lt;code&gt;--allow-unrelated-histories&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; merge upstream&#x2F;main&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --allow-unrelated-histories
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The changes from the original template will be merged. If there are conflicts between the parts you modified and the template updates, resolve them.&lt;&#x2F;p&gt;
&lt;p&gt;Once the conflicts have been resolved, commit the changes.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, push them to your own repository and you are done.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>About Me</title>
        <published>2026-09-22T00:00:00+00:00</published>
        <updated>2026-09-22T00:00:00+00:00</updated>
        <author>
          <name>Unknown</name>
        </author>
        <link rel="alternate" href="https://mosaos.github.io/about/" type="text/html"/>
        <id>https://mosaos.github.io/about/</id>
        
        <content type="html">&lt;h2 id=&quot;profile&quot;&gt;Profile&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Name&lt;&#x2F;strong&gt;: mosaos&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Occupation&lt;&#x2F;strong&gt;: Senior Engineer &#x2F; System Architect &#x2F; Tech Lead &#x2F; Instructor&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Areas of Activity&lt;&#x2F;strong&gt;: Covers a wide range of areas, from low-level technologies (physical control, KVM, and infrastructure) to web application development, facilitation of large-scale projects, and organizational education.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;technical-summary&quot;&gt;Technical Summary&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;【An Architect Who Can Complete Everything from Physical Control and Databases to Facilitation of Large-Scale Projects】&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Outstanding problem-solving ability and risk management:&lt;&#x2F;strong&gt;
During a period of rapid service growth, I responded to a critical database load problem by quickly conducting a PoC and proceeding with an online table type change. Even when design problems were discovered just before a release, I presented a realistic improvement roadmap that prioritized business impact and led the project to success.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Facilitation for organizing chaotic situations:&lt;&#x2F;strong&gt;
In meetings where coordination between stakeholders was difficult, I used a whiteboard to visualize the issues and identify their essential points. I solved complex coordination issues in a simple way and received high evaluations from experts.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Architecture design and performance optimization:&lt;&#x2F;strong&gt;
Rather than staying at the theoretical level, I cover a wide range from low-level technologies to web development, including building high-performance REST APIs with Seasar2 + JAX-RS (Jersey) and implementing video filters in C++.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Specialist in practical, hands-on education:&lt;&#x2F;strong&gt;
I have trained a total of several hundred engineers for practical work through an original curriculum that emphasizes active recall.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;FinOps &amp;amp; DevOps:&lt;&#x2F;strong&gt;
Cost optimization through AWS CUR visualization, as well as building DevOps environments (GitLab-CI&#x2F;Sentry, etc.) on a self-built KVM platform.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;main-career&quot;&gt;Main Career&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Current&lt;&#x2F;strong&gt;: Working at a company in Tokyo, engaged in application development and management of an engineering group, as well as promoting and leading internal study sessions and virtualization&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Best Practices for cron</title>
        <published>2026-09-22T00:00:00+00:00</published>
        <updated>2026-09-22T00:00:00+00:00</updated>
        <author>
          <name>Unknown</name>
        </author>
        <link rel="alternate" href="https://mosaos.github.io/blog/best-practice-cron/" type="text/html"/>
        <id>https://mosaos.github.io/blog/best-practice-cron/</id>
        
        <content type="html">&lt;p&gt;An issue occurred when temporarily stopping cron, which led to a discussion in a certain place about things such as change management. This is an overview of my best practices for cron.&lt;&#x2F;p&gt;
&lt;p&gt;* For now, I have just written down what I was thinking and what came to mind while listening to the discussion, so I may remember other things later or realize that &amp;quot;this was actually wrong after all.&amp;quot;&lt;br &#x2F;&gt;
* These are my personal cron tips, so feel free to customize them or optimize them for each project.&lt;&#x2F;p&gt;
&lt;p&gt;* This is a rewrite of an old article, so some parts may differ from the current environment.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;development&quot;&gt;Development&lt;&#x2F;h2&gt;
&lt;p&gt;First, some practices from the development side (cron implementers&#x2F;configurators).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;use-etc-cron-d&quot;&gt;Use &#x2F;etc&#x2F;cron.d&lt;&#x2F;h3&gt;
&lt;p&gt;Assuming that it is supported by the environment you are using, use &lt;code&gt;&#x2F;etc&#x2F;cron.d&#x2F;&lt;&#x2F;code&gt; if possible.&lt;br &#x2F;&gt;
* Do not edit crontab directly with &lt;code&gt;crontab -e&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Specifically, place multiple crontab configuration files under &lt;code&gt;&#x2F;etc&#x2F;cron.d&#x2F;&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ls&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;etc&#x2F;cron.d&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;system-a
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;system-b
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Example of system-a:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# system-a cron jobs
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;SHELL&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;bin&#x2F;bash
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;PATH&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;sbin:&#x2F;bin:&#x2F;usr&#x2F;sbin:&#x2F;usr&#x2F;bin
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;MAILTO&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;root
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;0 &lt;&#x2F;span&gt;&lt;span&gt;* * * *  sysauser sysa-task01
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;30 &lt;&#x2F;span&gt;&lt;span&gt;* * * * sysauser sysa-task02
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This provides the following benefits:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;crontab settings can be grouped in a meaningful way.&lt;&#x2F;li&gt;
&lt;li&gt;By assigning appropriate permissions to individual configurations, it is also possible to prevent unnecessary modification of crontab settings for other systems.&lt;&#x2F;li&gt;
&lt;li&gt;It works better when version-controlling them, just like cron shell scripts (described below).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Allowing individual users to have their own cron settings (users editing them with &lt;code&gt;crontab -e&lt;&#x2F;code&gt;) is also OK, but in many cases, I think there are relatively few use cases where individual users need to use cron.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;use-shell-scripts-to-execute-tasks&quot;&gt;Use shell scripts to execute tasks&lt;&#x2F;h3&gt;
&lt;p&gt;For simple commands or processes that can be executed with a one-liner, it is possible to directly specify system or middleware commands in crontab.&lt;&#x2F;p&gt;
&lt;p&gt;However, when executing tasks managed by an organization, I recommend always creating a shell script to execute the task and implementing the processing in that file. Then, specify the shell script to be executed in crontab.&lt;&#x2F;p&gt;
&lt;p&gt;This provides the following benefits:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The handling of environment variables differs when cron runs a command from when a user logs in, which can sometimes cause problems. By using a shell script, it becomes easy to set the environment variables required before executing commands, or to change them when necessary.&lt;&#x2F;li&gt;
&lt;li&gt;By version-controlling the shell script itself, it becomes possible to track the history of changes to the processing, and to perform appropriate reviews by going through a PR&#x2F;MR process.&lt;&#x2F;li&gt;
&lt;li&gt;It also becomes easy to call another script for common processing (such as setting environment variables, notifications, or logging) from the script specified in cron before calling the actual processing.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;establish-coding-rules-for-scripts&quot;&gt;Establish coding rules for scripts&lt;&#x2F;h3&gt;
&lt;p&gt;I don&#x27;t think it is necessary to make the rules too strict, but it is better to unify the level of description and processing as much as possible, for example by preparing an easy-to-understand template.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Write comments at an appropriate level of detail.&lt;&#x2F;li&gt;
&lt;li&gt;Turn values that may change into variables.&lt;&#x2F;li&gt;
&lt;li&gt;Define common processing and use it.
For example, make it a common script and call it.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;use-version-control&quot;&gt;Use version control&lt;&#x2F;h3&gt;
&lt;p&gt;The reasons for using version control include, of course, being able to restore the previous version or check differences when a problem occurs. However, the following points should also be aimed for.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Deployment using CI&#x2F;CD&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
At present, I think the number of projects that use CI&#x2F;CD for application deployment is increasing, but Linux scripts, cron configurations, and so on should also be managed using a version control system and deployed using CI&#x2F;CD.&lt;br &#x2F;&gt;
This is also related to concepts proposed by &lt;a href=&quot;https:&#x2F;&#x2F;12factor.net&quot;&gt;The Twelve Factor App&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Reviews using PR&#x2F;MR&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
When an incident occurs related to a release or change, I feel like I have heard the following kinds of explanations many times:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;One person did the work.&lt;&#x2F;li&gt;
&lt;li&gt;There was no checking process, or it was not functioning.&lt;&#x2F;li&gt;
&lt;li&gt;No review was performed.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;And then, as a countermeasure: &amp;quot;We will make sure to do it properly from now on.&amp;quot;&lt;&#x2F;p&gt;
&lt;p&gt;However, with this kind of countermeasure, even if you only put up a slogan, things often return to the way they were after a while.
It is more effective to use the power of systems&#x2F;tools by always using PR&#x2F;MR (Pull Request&#x2F;Merge Request) so that checks are always performed.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;* GitLab should also allow you to restrict permissions for pushing. If you are going to require MRs, restrict direct pushes to designated branches, for example. Use tools to enforce the rules rather than relying on slogans.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;prevent-multiple-executions&quot;&gt;Prevent multiple executions&lt;&#x2F;h3&gt;
&lt;p&gt;When implementing an application, it is possible to use mechanisms provided by the processing language (such as Java) to prevent multiple executions. However, multiple executions can also be prevented by using &lt;code&gt;flock&lt;&#x2F;code&gt;, a standard Linux tool.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;*&#x2F;5 &lt;&#x2F;span&gt;&lt;span&gt;* * * *  appuser  flock&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -n&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;var&#x2F;lock&#x2F;cron-task.lock cron-task
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Here is an actual example.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;script&quot;&gt;Script&lt;&#x2F;h4&gt;
&lt;p&gt;Create a script containing the processing.&lt;&#x2F;p&gt;
&lt;p&gt;Create &lt;code&gt;&#x2F;root&#x2F;scripts&#x2F;sleep.sh&lt;&#x2F;code&gt; as follows.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;#!&#x2F;bin&#x2F;bash
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;INTERVAL&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;300
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;sleep &lt;&#x2F;span&gt;&lt;span&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;INTERVAL
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;echo  &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;INTERVAL&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt; sec slept&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It simply sleeps for the number of seconds specified by the interval and then outputs a message with &lt;code&gt;echo&lt;&#x2F;code&gt;.
It is configured so that the job continues for 300 seconds (5 minutes).&lt;&#x2F;p&gt;
&lt;h4 id=&quot;cron-configuration&quot;&gt;cron configuration&lt;&#x2F;h4&gt;
&lt;p&gt;For the cron configuration, create &lt;code&gt;&#x2F;etc&#x2F;cron.d&#x2F;test&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# put some comment here
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;* &lt;&#x2F;span&gt;&lt;span&gt;* * * * root flock&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -n&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;var&#x2F;lock&#x2F;cron-test-sleep.lock &#x2F;root&#x2F;scripts&#x2F;sleep.sh
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;flock&lt;&#x2F;code&gt; prevents multiple executions.
It runs at one-minute intervals.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;execution-result&quot;&gt;Execution result&lt;&#x2F;h4&gt;
&lt;p&gt;Output from &lt;code&gt;&#x2F;var&#x2F;log&#x2F;cron&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Feb&lt;&#x2F;span&gt;&lt;span&gt;  8 16:07:01 mosaos-dev CROND&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;7083&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;: (root) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CMD&lt;&#x2F;span&gt;&lt;span&gt; (flock&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -n&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;var&#x2F;lock&#x2F;cron-test-sleep.lock &#x2F;root&#x2F;scripts&#x2F;sleep.sh)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Feb&lt;&#x2F;span&gt;&lt;span&gt;  8 16:08:01 mosaos-dev CROND&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;7087&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;: (root) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CMD&lt;&#x2F;span&gt;&lt;span&gt; (flock&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -n&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;var&#x2F;lock&#x2F;cron-test-sleep.lock &#x2F;root&#x2F;scripts&#x2F;sleep.sh)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Feb&lt;&#x2F;span&gt;&lt;span&gt;  8 16:09:01 mosaos-dev CROND&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;7089&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;: (root) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CMD&lt;&#x2F;span&gt;&lt;span&gt; (flock&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -n&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;var&#x2F;lock&#x2F;cron-test-sleep.lock &#x2F;root&#x2F;scripts&#x2F;sleep.sh)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Feb&lt;&#x2F;span&gt;&lt;span&gt;  8 16:10:01 mosaos-dev CROND&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;7091&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;: (root) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CMD&lt;&#x2F;span&gt;&lt;span&gt; (flock&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -n&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;var&#x2F;lock&#x2F;cron-test-sleep.lock &#x2F;root&#x2F;scripts&#x2F;sleep.sh)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Feb&lt;&#x2F;span&gt;&lt;span&gt;  8 16:11:01 mosaos-dev CROND&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;7093&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;: (root) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CMD&lt;&#x2F;span&gt;&lt;span&gt; (flock&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -n&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;var&#x2F;lock&#x2F;cron-test-sleep.lock &#x2F;root&#x2F;scripts&#x2F;sleep.sh)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Feb&lt;&#x2F;span&gt;&lt;span&gt;  8 16:12:01 mosaos-dev CROND&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;7082&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;: (root) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CMDOUT&lt;&#x2F;span&gt;&lt;span&gt; (300 sec slept)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Feb&lt;&#x2F;span&gt;&lt;span&gt;  8 16:12:01 mosaos-dev CROND&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;7096&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;: (root) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CMD&lt;&#x2F;span&gt;&lt;span&gt; (flock&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -n&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;var&#x2F;lock&#x2F;cron-test-sleep.lock &#x2F;root&#x2F;scripts&#x2F;sleep.sh)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Feb&lt;&#x2F;span&gt;&lt;span&gt;  8 16:13:01 mosaos-dev CROND&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;7100&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;: (root) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CMD&lt;&#x2F;span&gt;&lt;span&gt; (flock&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -n&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;var&#x2F;lock&#x2F;cron-test-sleep.lock &#x2F;root&#x2F;scripts&#x2F;sleep.sh)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Feb&lt;&#x2F;span&gt;&lt;span&gt;  8 16:14:01 mosaos-dev CROND&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;7102&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;: (root) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CMD&lt;&#x2F;span&gt;&lt;span&gt; (flock&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -n&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;var&#x2F;lock&#x2F;cron-test-sleep.lock &#x2F;root&#x2F;scripts&#x2F;sleep.sh)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Feb&lt;&#x2F;span&gt;&lt;span&gt;  8 16:15:01 mosaos-dev CROND&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;7104&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;: (root) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CMD&lt;&#x2F;span&gt;&lt;span&gt; (flock&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -n&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;var&#x2F;lock&#x2F;cron-test-sleep.lock &#x2F;root&#x2F;scripts&#x2F;sleep.sh)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Feb&lt;&#x2F;span&gt;&lt;span&gt;  8 16:16:01 mosaos-dev CROND&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;7108&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;: (root) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CMD&lt;&#x2F;span&gt;&lt;span&gt; (flock&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -n&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;var&#x2F;lock&#x2F;cron-test-sleep.lock &#x2F;root&#x2F;scripts&#x2F;sleep.sh)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Feb&lt;&#x2F;span&gt;&lt;span&gt;  8 16:17:01 mosaos-dev CROND&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;7095&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;: (root) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CMDOUT&lt;&#x2F;span&gt;&lt;span&gt; (300 sec slept)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The cron job runs at one-minute intervals, but you can see that the actual processing (&lt;code&gt;echo&lt;&#x2F;code&gt;) occurs at five-minute intervals.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;use-timeouts&quot;&gt;Use timeouts&lt;&#x2F;h3&gt;
&lt;p&gt;Depending on the type of task, using a timeout can be useful.&lt;&#x2F;p&gt;
&lt;p&gt;Normally, jobs executed by cron run without a time limit, but this may not always be desirable.&lt;&#x2F;p&gt;
&lt;p&gt;For example, for a job that runs at regular intervals, if it does not finish within a certain amount of time, the job may be executed again while the previous execution is still running.&lt;&#x2F;p&gt;
&lt;p&gt;In such cases, try using &lt;code&gt;timeout&lt;&#x2F;code&gt; (&lt;code&gt;&#x2F;usr&#x2F;bin&#x2F;timeout&lt;&#x2F;code&gt;) or something similar to limit the execution time.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;*&#x2F;5 &lt;&#x2F;span&gt;&lt;span&gt;* * * *  appuser  timeout 10s cron-task
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As with &lt;code&gt;flock&lt;&#x2F;code&gt;, here is an actual example.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;script-1&quot;&gt;Script&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;#!&#x2F;bin&#x2F;bash
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;while &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;true
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;do
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;date
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;sleep&lt;&#x2F;span&gt;&lt;span&gt; 1
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;done
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Outputs &lt;code&gt;date&lt;&#x2F;code&gt; at one-second intervals.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;cron-configuration-1&quot;&gt;cron configuration&lt;&#x2F;h4&gt;
&lt;p&gt;Edit the &lt;code&gt;&#x2F;etc&#x2F;cron.d&#x2F;test&lt;&#x2F;code&gt; file.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# put some comment here
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;* &lt;&#x2F;span&gt;&lt;span&gt;* * * * root timeout 10s &#x2F;root&#x2F;scripts&#x2F;loop.sh
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Timeout after 10 seconds.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;execution-result-1&quot;&gt;Execution result&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Feb&lt;&#x2F;span&gt;&lt;span&gt;  8 16:49:01 mosaos-dev CROND&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;7261&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;: (root) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CMD&lt;&#x2F;span&gt;&lt;span&gt; (timeout 10s &#x2F;root&#x2F;scripts&#x2F;loop.sh)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Feb&lt;&#x2F;span&gt;&lt;span&gt;  8 16:49:01 mosaos-dev CROND&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;7260&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;: (root) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CMDOUT&lt;&#x2F;span&gt;&lt;span&gt; (2022年  2月  8日 火曜日 16:49:01 JST)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Feb&lt;&#x2F;span&gt;&lt;span&gt;  8 16:49:02 mosaos-dev CROND&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;7260&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;: (root) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CMDOUT&lt;&#x2F;span&gt;&lt;span&gt; (2022年  2月  8日 火曜日 16:49:02 JST)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Feb&lt;&#x2F;span&gt;&lt;span&gt;  8 16:49:03 mosaos-dev CROND&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;7260&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;: (root) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CMDOUT&lt;&#x2F;span&gt;&lt;span&gt; (2022年  2月  8日 火曜日 16:49:03 JST)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Feb&lt;&#x2F;span&gt;&lt;span&gt;  8 16:49:04 mosaos-dev CROND&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;7260&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;: (root) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CMDOUT&lt;&#x2F;span&gt;&lt;span&gt; (2022年  2月  8日 火曜日 16:49:04 JST)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Feb&lt;&#x2F;span&gt;&lt;span&gt;  8 16:49:05 mosaos-dev CROND&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;7260&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;: (root) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CMDOUT&lt;&#x2F;span&gt;&lt;span&gt; (2022年  2月  8日 火曜日 16:49:05 JST)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Feb&lt;&#x2F;span&gt;&lt;span&gt;  8 16:49:06 mosaos-dev CROND&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;7260&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;: (root) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CMDOUT&lt;&#x2F;span&gt;&lt;span&gt; (2022年  2月  8日 火曜日 16:49:06 JST)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Feb&lt;&#x2F;span&gt;&lt;span&gt;  8 16:49:07 mosaos-dev CROND&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;7260&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;: (root) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CMDOUT&lt;&#x2F;span&gt;&lt;span&gt; (2022年  2月  8日 火曜日 16:49:07 JST)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Feb&lt;&#x2F;span&gt;&lt;span&gt;  8 16:49:08 mosaos-dev CROND&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;7260&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;: (root) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CMDOUT&lt;&#x2F;span&gt;&lt;span&gt; (2022年  2月  8日 火曜日 16:49:08 JST)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Feb&lt;&#x2F;span&gt;&lt;span&gt;  8 16:49:09 mosaos-dev CROND&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;7260&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;: (root) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CMDOUT&lt;&#x2F;span&gt;&lt;span&gt; (2022年  2月  8日 火曜日 16:49:09 JST)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Feb&lt;&#x2F;span&gt;&lt;span&gt;  8 16:49:10 mosaos-dev CROND&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;7260&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;: (root) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CMDOUT&lt;&#x2F;span&gt;&lt;span&gt; (2022年  2月  8日 火曜日 16:49:10 JST)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Feb&lt;&#x2F;span&gt;&lt;span&gt;  8 16:50:01 mosaos-dev CROND&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;7287&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;: (root) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CMD&lt;&#x2F;span&gt;&lt;span&gt; (timeout 10s &#x2F;root&#x2F;scripts&#x2F;loop.sh)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Feb&lt;&#x2F;span&gt;&lt;span&gt;  8 16:50:01 mosaos-dev CROND&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;7286&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;: (root) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CMDOUT&lt;&#x2F;span&gt;&lt;span&gt; (2022年  2月  8日 火曜日 16:50:01 JST)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Feb&lt;&#x2F;span&gt;&lt;span&gt;  8 16:50:02 mosaos-dev CROND&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;7286&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;: (root) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CMDOUT&lt;&#x2F;span&gt;&lt;span&gt; (2022年  2月  8日 火曜日 16:50:02 JST)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Feb&lt;&#x2F;span&gt;&lt;span&gt;  8 16:50:03 mosaos-dev CROND&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;7286&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;: (root) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CMDOUT&lt;&#x2F;span&gt;&lt;span&gt; (2022年  2月  8日 火曜日 16:50:03 JST)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Feb&lt;&#x2F;span&gt;&lt;span&gt;  8 16:50:04 mosaos-dev CROND&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;7286&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;: (root) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CMDOUT&lt;&#x2F;span&gt;&lt;span&gt; (2022年  2月  8日 火曜日 16:50:04 JST)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Feb&lt;&#x2F;span&gt;&lt;span&gt;  8 16:50:05 mosaos-dev CROND&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;7286&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;: (root) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CMDOUT&lt;&#x2F;span&gt;&lt;span&gt; (2022年  2月  8日 火曜日 16:50:05 JST)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Feb&lt;&#x2F;span&gt;&lt;span&gt;  8 16:50:06 mosaos-dev CROND&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;7286&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;: (root) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CMDOUT&lt;&#x2F;span&gt;&lt;span&gt; (2022年  2月  8日 火曜日 16:50:06 JST)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Feb&lt;&#x2F;span&gt;&lt;span&gt;  8 16:50:07 mosaos-dev CROND&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;7286&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;: (root) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CMDOUT&lt;&#x2F;span&gt;&lt;span&gt; (2022年  2月  8日 火曜日 16:50:07 JST)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Feb&lt;&#x2F;span&gt;&lt;span&gt;  8 16:50:08 mosaos-dev CROND&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;7286&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;: (root) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CMDOUT&lt;&#x2F;span&gt;&lt;span&gt; (2022年  2月  8日 火曜日 16:50:08 JST)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Feb&lt;&#x2F;span&gt;&lt;span&gt;  8 16:50:09 mosaos-dev CROND&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;7286&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;: (root) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CMDOUT&lt;&#x2F;span&gt;&lt;span&gt; (2022年  2月  8日 火曜日 16:50:09 JST)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Feb&lt;&#x2F;span&gt;&lt;span&gt;  8 16:50:10 mosaos-dev CROND&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;7286&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;: (root) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CMDOUT&lt;&#x2F;span&gt;&lt;span&gt; (2022年  2月  8日 火曜日 16:50:10 JST)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can see that the processing is interrupted after 10 seconds. Depending on the task, terminating it midway may cause serious problems, so be careful about where you use this.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;operations&quot;&gt;Operations&lt;&#x2F;h2&gt;
&lt;p&gt;Operational practices.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;restrict-permissions&quot;&gt;Restrict permissions&lt;&#x2F;h3&gt;
&lt;p&gt;When running a cron job, specify the execution user appropriately and restrict its permissions.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;0 &lt;&#x2F;span&gt;&lt;span&gt;* * * *  root  cron-task
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The above crontab configuration specifies that it should be run as the root user. However, when it is executed as root, it can be difficult to impose restrictions, even if, for example, the execution job is something that could destroy an important part of a system directory.&lt;&#x2F;p&gt;
&lt;p&gt;It is better to create a user with the minimum permissions required for each application and specify that user instead.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;0 &lt;&#x2F;span&gt;&lt;span&gt;* * * *  appuser  cron-task
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;do-not-discard-output&quot;&gt;Do not discard output&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;*&#x2F;5 &lt;&#x2F;span&gt;&lt;span&gt;* * * *  appuser  cron-task &amp;gt;&#x2F;dev&#x2F;null &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Do not redirect output to &lt;code&gt;&#x2F;dev&#x2F;null&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;When looking at examples on the Internet and copying them as they are, there may be cases where output is discarded without really understanding why.&lt;&#x2F;p&gt;
&lt;p&gt;However, this means throwing away clues that could be useful when a problem occurs, so unless there is a specific reason, do not discard the output.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;other&quot;&gt;Other&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;I have seen many environments where, in incident management, a ticket is closed after simply dealing with the incident without taking any measures to prevent it from happening again. In such environments, problems caused by simple carelessness are likely to continue occurring in the future.&lt;br &#x2F;&gt;
If similar problems occur frequently, it may be better to consider introducing a platform (job management tool) that makes this kind of problem less likely to occur.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;If commercial management tools are expensive... open source is also an option. For example, &lt;a href=&quot;https:&#x2F;&#x2F;dolphinscheduler.apache.org&#x2F;&quot;&gt;DolphinScheduler&lt;&#x2F;a&gt;.&lt;br &#x2F;&gt;
I have never used it, but judging from the screenshots, it looks pretty good. If it really is what it claims to be, a &amp;quot;big data distributed workflow scheduling system,&amp;quot; it may be usable for some time to come.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;If containerization will be promoted in the future, use &lt;a href=&quot;https:&#x2F;&#x2F;kubernetes.io&#x2F;docs&#x2F;concepts&#x2F;workloads&#x2F;controllers&#x2F;cron-jobs&#x2F;&quot;&gt;CronJob&lt;&#x2F;a&gt; in Kubernetes, for example.&lt;br &#x2F;&gt;
Keep in mind that the optimal choice may differ depending on the platform.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Even if there are best practices, they are meaningless if the individual developers and operations staff responsible for implementation do not follow them.&lt;br &#x2F;&gt;
Rather than handling this at the project or individual level, the company as a whole should establish a certain level of policy and roll out the best practices across the organization.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Best Practices for GitLab</title>
        <published>2026-09-22T00:00:00+00:00</published>
        <updated>2026-09-22T00:00:00+00:00</updated>
        <author>
          <name>Unknown</name>
        </author>
        <link rel="alternate" href="https://mosaos.github.io/blog/best-practice-gitlab/" type="text/html"/>
        <id>https://mosaos.github.io/blog/best-practice-gitlab/</id>
        
        <content type="html">&lt;p&gt;The Best Practices series.&lt;&#x2F;p&gt;
&lt;p&gt;My personal GitLab practices, so to speak.&lt;&#x2F;p&gt;
&lt;p&gt;* This is a rewrite of an old article, so some parts may differ from the current GitLab UI.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;I have had both things that worked well and things that did not work well while using GitHub personally and GitLab for work.&lt;&#x2F;p&gt;
&lt;p&gt;Based on these experiences, I will summarize some Tips such as:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Things that may work well if you do them this way.&lt;&#x2F;li&gt;
&lt;li&gt;Things that may fail if you do them this way.&lt;&#x2F;li&gt;
&lt;li&gt;Features that may be useful if you use them.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;* These are my personal Tips, so feel free to customize them as appropriate for each project.&lt;&#x2F;p&gt;
&lt;p&gt;* I will also describe some features that are probably rarely used at workplaces. Using them may improve the quality of a project.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;git&quot;&gt;Git&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;Learn the basic operations yourself.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;If you use GitLab, you will probably use Git.&lt;&#x2F;p&gt;
&lt;p&gt;* There may be cases where Issue management is not used (for example, Redmine is used for task management while GitLab is used for source management, resulting in a mix of management tools).&lt;&#x2F;p&gt;
&lt;p&gt;If you are not confident about how to use Git, use methods such as the following to master the basic operations.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Learn &#x2F; research by yourself (books &#x2F; Internet)&lt;&#x2F;li&gt;
&lt;li&gt;Get used to it personally using GitHub, etc.&lt;&#x2F;li&gt;
&lt;li&gt;Ask someone who knows it well.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Some companies may have few people who will teach someone from scratch when they have no idea what they are doing.&lt;&#x2F;p&gt;
&lt;p&gt;If you are not confident about the operations, randomly touching and breaking a branch that is actually in operation may be something that could get you kicked out depending on the company&#x2F;project. Prepare a test repository and practice.&lt;&#x2F;p&gt;
&lt;p&gt;If you break the production environment without even practicing, you cannot really complain if people regard you as incompetent.&lt;&#x2F;p&gt;
&lt;p&gt;It is also possible to build an environment including GitLab + GitLab Runner with docker-compose, so if you want to experiment with various things, I recommend building the environment with Docker.&lt;&#x2F;p&gt;
&lt;p&gt;* I once saw someone who was not confident about how to use either Git or SVN, and people jokingly wondered whether they were really a developer (they weren&#x27;t lying about their career history, were they?).&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;permission-management&quot;&gt;Permission Management&lt;&#x2F;h2&gt;
&lt;p&gt;When adding members to a project, assign appropriate roles.&lt;&#x2F;p&gt;
&lt;p&gt;In &lt;a href=&quot;..&#x2F;best-practice-cron&#x2F;&quot;&gt;Best Practices for cron&lt;&#x2F;a&gt;, I wrote:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;* GitLab should also allow you to restrict permissions for pushing. If you are going to require MRs, restrict direct pushes to designated branches, for example. Use tools to enforce the rules rather than relying on slogans.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;When taking measures such as the above, you need to configure the settings so that merge&#x2F;push to specific branches is allowed only for members with a specific role or higher.&lt;br &#x2F;&gt;
* This can be configured from [&lt;code&gt;Settings&lt;&#x2F;code&gt;] &amp;gt; [&lt;code&gt;Repository&lt;&#x2F;code&gt;] &amp;gt; [&lt;code&gt;Protected branches&lt;&#x2F;code&gt;] in the project.&lt;&#x2F;p&gt;
&lt;p&gt;However, if everyone, including members of partner companies, has &lt;code&gt;Maintainer&lt;&#x2F;code&gt; permissions, appropriate restrictions cannot be enforced even if you configure the above settings.&lt;&#x2F;p&gt;
&lt;p&gt;I mentioned the inability to properly restrict functionality, but this is a security problem in the first place.&lt;&#x2F;p&gt;
&lt;p&gt;Maintainer permissions should be limited to employees only (preferably to a limited number of members who can make the appropriate settings), while normal developers should be assigned Developer permissions.&lt;&#x2F;p&gt;
&lt;p&gt;* From an audit perspective as well, assigning unnecessary permissions without a reason is probably not acceptable.&lt;&#x2F;p&gt;
&lt;p&gt;The following kind of situation is something I have seen fairly often even in companies, as is also the case with Redmine:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why does this member have this role? The permission assignment is basically a free-for-all.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Giving permissions simply because they seem convenient is not a good idea. If you are doing this, fix it.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;branch-strategy&quot;&gt;Branch Strategy&lt;&#x2F;h2&gt;
&lt;p&gt;For projects that are already in operation, I assume there is a branch strategy for each project.&lt;&#x2F;p&gt;
&lt;p&gt;If there is already a defined way of operating the project and it is working well, use it.&lt;&#x2F;p&gt;
&lt;p&gt;Here is an example of a branch strategy I used in the past.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;mosaos.github.io&#x2F;blog&#x2F;best-practice-gitlab&#x2F;mosaos-gitflow.webp&quot; alt=&quot;git branch&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;* It is similar to gitflow, so if you have used gitflow before, it should be easy to understand.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;master&lt;&#x2F;code&gt;(or &lt;code&gt;main&lt;&#x2F;code&gt;)&lt;br &#x2F;&gt;
For releases. It is deployed to the production environment.&lt;br &#x2F;&gt;
Do not edit master directly.&lt;br &#x2F;&gt;
When merging into master, create a tag.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;develop&lt;&#x2F;code&gt;&lt;br &#x2F;&gt;
The main development branch. Created from master.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;feature&lt;&#x2F;code&gt;&lt;br &#x2F;&gt;
A branch for each issue.&lt;br &#x2F;&gt;
Created from the latest develop.&lt;br &#x2F;&gt;
The branch name was &lt;code&gt;feature&#x2F;issueNNN&lt;&#x2F;code&gt; (NNN is the issue number).&lt;br &#x2F;&gt;
A separate branch is created for each issue, and after implementation is completed, it is merged into develop.&lt;br &#x2F;&gt;
* Initially, there was also an idea of creating development branches for individual members rather than creating them by function. (A member had used that approach before.) However, with this approach, one functional change could span multiple branches (for example, when different developers are responsible for the frontend and server-side), so we stopped using this method.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;hotfix&lt;&#x2F;code&gt;&lt;br &#x2F;&gt;
Used when a critical bug occurs in master.&lt;br &#x2F;&gt;
Created from master where the critical bug occurred.&lt;br &#x2F;&gt;
The branch name is &lt;code&gt;hotfix&#x2F;issueNNN&lt;&#x2F;code&gt; (NNN is the issue number).&lt;br &#x2F;&gt;
After fixing the bug, it is merged into master.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;When merging, create an MR and merge after review.&lt;&#x2F;p&gt;
&lt;p&gt;* Depending on the project member structure and the contents of the MR, self-review was allowed.&lt;&#x2F;p&gt;
&lt;p&gt;* The above rules work more easily when ticket-driven development is adopted as the development method (because an issue should always have been created). What should you do if you are not using ticket-driven development? Just make it ticket-driven development! (Recommended.)&lt;&#x2F;p&gt;
&lt;p&gt;* By the way, I once used the &lt;code&gt;feature&#x2F;#NNN&lt;&#x2F;code&gt; format for branch names, but this format was discontinued because having &lt;code&gt;#&lt;&#x2F;code&gt; in a branch name caused problems with links to GitLab (the link did not work from Slack notifications). It is better not to include &lt;code&gt;#&lt;&#x2F;code&gt; in branch names.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;creating-branches&quot;&gt;Creating Branches&lt;&#x2F;h2&gt;
&lt;p&gt;When adding a new feature or fixing a bug, create a branch according to the &lt;code&gt;branch strategy&lt;&#x2F;code&gt; defined&#x2F;adopted by the project.&lt;&#x2F;p&gt;
&lt;p&gt;Branches can also be created on GitLab, but this has the following side effects.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;If you use &lt;code&gt;New Branch&lt;&#x2F;code&gt; on GitLab, the created branch is committed&#x2F;pushed, so CI&#x2F;CD (Pipeline) is executed.&lt;br &#x2F;&gt;
It would be nice if there were a way to determine in gitlab-ci.yml whether &lt;code&gt;New Branch&lt;&#x2F;code&gt; was used from GitLab, but apparently this cannot currently be determined, so CI&#x2F;CD is executed just by using &lt;code&gt;New Branch&lt;&#x2F;code&gt;.&lt;br &#x2F;&gt;
This is inconvenient for the following reasons:
&lt;ul&gt;
&lt;li&gt;Unnecessary CI&#x2F;CD runs. Various resources are wasted (computing resources, time, storage on the remote repository, etc.).&lt;&#x2F;li&gt;
&lt;li&gt;It is easier to discover problems in CI&#x2F;CD (Pipeline) if CI&#x2F;CD runs only when a feature addition, bug fix, etc. is pushed. If a Pipeline runs every time a branch is created, there is a possibility that Pipelines will no longer be checked properly.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Based on the above, unless there is a special reason, I recommend creating branches using the following procedure.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Create a branch locally from the source branch.&lt;&#x2F;li&gt;
&lt;li&gt;Using the created local branch, make some changes (feature addition, bug fix, etc.), then build and test it locally.&lt;&#x2F;li&gt;
&lt;li&gt;Commit locally.&lt;&#x2F;li&gt;
&lt;li&gt;Push to the remote (GitLab).&lt;br &#x2F;&gt;
For a newly created branch, the branch is created on the remote for the first time at this point, and CI&#x2F;CD is executed.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;The advantages of using the above procedure are as follows.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The remote branch is not created until an actual change (local Commit) is reflected (Push).&lt;br &#x2F;&gt;
You may create a branch but ultimately not Commit&#x2F;Push anything. In this case, no GitLab resources are wasted.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Unnecessary CI&#x2F;CD does not run.&lt;br &#x2F;&gt;
When &lt;code&gt;New Branch&lt;&#x2F;code&gt; is used on GitLab, CI&#x2F;CD runs as described above. This means that the state of the latest commit on the branch from which the new branch was created (such as develop) is run through CI&#x2F;CD again. Running CI&#x2F;CD again for a Commit&#x2F;Push that has already been checked by CI&#x2F;CD is unnecessary.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;The Pipeline history does not get cluttered.&lt;br &#x2F;&gt;
Related to the above, unnecessary Pipelines leave execution history that should not have been there in the first place. If a problem occurs in CI&#x2F;CD and you need to investigate the past history, having a lot of this kind of history increases the investigation cost.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;You can create branches in a development environment such as VSCode without using &lt;code&gt;New Branch&lt;&#x2F;code&gt; on GitLab. Create branches using the procedure above.&lt;&#x2F;p&gt;
&lt;p&gt;* Most members were creating branches using the above procedure, but at one point a situation occurred where a Pipeline was executed when some members used New Branch on GitLab. This resulted in &amp;quot;What is this Pipeline?&amp;quot;, so I documented and rolled out the above procedure at the time.&lt;&#x2F;p&gt;
&lt;p&gt;* Some people may say, &amp;quot;Our project doesn&#x27;t use CI, so it doesn&#x27;t matter.&amp;quot; However, there is always a possibility that CI will be introduced in the future. Fixing a method that members have already become accustomed to can be costly (depending on the members). I think it is better to adopt a method that causes fewer problems.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;commits&quot;&gt;Commits&lt;&#x2F;h2&gt;
&lt;p&gt;When committing, write an appropriate commit message.&lt;&#x2F;p&gt;
&lt;p&gt;When using ticket-driven development with GitLab, a commit is work corresponding to a ticket (issue) that was created beforehand, so include the issue ID in the commit message.&lt;&#x2F;p&gt;
&lt;p&gt;This automatically associates the issue and commit (cross-links are created).&lt;&#x2F;p&gt;
&lt;p&gt;When specifying the issue ID, use the &lt;code&gt;#nnn&lt;&#x2F;code&gt; format (nnn is the issue ID (a decimal number)).&lt;&#x2F;p&gt;
&lt;p&gt;Writing it at the beginning of the commit message makes it easy to understand and less likely to be forgotten.&lt;&#x2F;p&gt;
&lt;p&gt;* I have seen cases where someone put a space between &lt;code&gt;#&lt;&#x2F;code&gt; and &lt;code&gt;nnn&lt;&#x2F;code&gt;, as in &lt;code&gt;# nnn&lt;&#x2F;code&gt;, and the link was not created, so do not put a space between them.&lt;&#x2F;p&gt;
&lt;p&gt;* Even when tickets themselves are managed with Redmine, it is also possible to integrate them with the Git repository by using Redmine&#x27;s repository feature (additional configuration is required).&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;merge-requests&quot;&gt;Merge Requests&lt;&#x2F;h2&gt;
&lt;p&gt;When performing a merge, always create a merge request (MR).&lt;br &#x2F;&gt;
(Do not merge without an MR.)&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Click &lt;code&gt;Merge requests&lt;&#x2F;code&gt; from the GitLab menu.&lt;&#x2F;li&gt;
&lt;li&gt;The MR list screen will be displayed, so click the &lt;code&gt;New merge request&lt;&#x2F;code&gt; button.&lt;&#x2F;li&gt;
&lt;li&gt;Two branch input fields, Source &#x2F; Target, will be displayed, so set each branch.&lt;br &#x2F;&gt;
When doing normal feature development, they will be as follows. (This differs for hotfixes and merges to master. If you are unsure, consult someone knowledgeable.)&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Source branch&lt;&#x2F;code&gt;: the branch to be merged (&lt;code&gt;feature&#x2F;issueNNN&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Target branch&lt;&#x2F;code&gt;: the branch to merge into (&lt;code&gt;develop&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Click &lt;code&gt;Compare branches and continue&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;You will be taken to the New merge request screen, so first check the changes.&lt;br &#x2F;&gt;
If you scroll down the screen, the &lt;code&gt;Commits&lt;&#x2F;code&gt;, &lt;code&gt;Pipelines&lt;&#x2F;code&gt;, and &lt;code&gt;Changes&lt;&#x2F;code&gt; tabs are displayed. Check that the following are correct. If there is a problem, stop creating the MR for the time being, resolve any problems with the branch creation procedure or file editing, and then create the MR again.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Commits&lt;&#x2F;code&gt;&lt;br &#x2F;&gt;
The commits included in the MR. If commits containing content different from what you are trying to merge are included, assume that there is some kind of problem.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Changes&lt;&#x2F;code&gt;&lt;br &#x2F;&gt;
The file differences before and after the MR are included. Check whether the differences (changes) are correct. If changes that you did not make, or incorrect changes, are included, assume that there is some kind of problem.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;If there are no problems with &lt;code&gt;Commits&lt;&#x2F;code&gt; or &lt;code&gt;Changes&lt;&#x2F;code&gt;, configure the following MR contents as appropriate.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Title&lt;&#x2F;code&gt;&lt;br &#x2F;&gt;
Set the MR title as appropriate.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Description&lt;&#x2F;code&gt;&lt;br &#x2F;&gt;
It is a good idea to write an overview of the changes included in the MR.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Reviewer&lt;&#x2F;code&gt;&lt;br &#x2F;&gt;
If you want someone to review the MR, set that member as a reviewer. Even if you set this in GitLab, the other person may not notice it, so I recommend also notifying them that you would like a review via Slack or another means.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;ol start=&quot;7&quot;&gt;
&lt;li&gt;Click &lt;code&gt;Create merge request&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;The member who was asked to review checks whether there are any problems with the MR and comments on the MR if necessary.&lt;&#x2F;li&gt;
&lt;li&gt;The MR creator explains the reviewer&#x27;s comments, makes code changes, etc., and resolves the issues.&lt;&#x2F;li&gt;
&lt;li&gt;Repeat the 6 -&amp;gt; 7 process until there are no problems, then the reviewer clicks the MR&#x27;s &lt;code&gt;Approve&lt;&#x2F;code&gt; button.&lt;&#x2F;li&gt;
&lt;li&gt;The MR creator (or the member assigned to the MR) confirms that it has been Approved and clicks the &lt;code&gt;Merge&lt;&#x2F;code&gt; button.&lt;br &#x2F;&gt;
By default, &lt;code&gt;Delete source branch&lt;&#x2F;code&gt; is checked. If you do not want to delete the source branch (&lt;code&gt;feature&#x2F;issueNNN&lt;&#x2F;code&gt;, etc.) after merging because you will continue working on that branch, uncheck it before clicking the &lt;code&gt;Merge&lt;&#x2F;code&gt; button.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;This is also effective for preventing problems such as the following, which sometimes occur even in companies:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;One person did all the work.&lt;&#x2F;li&gt;
&lt;li&gt;There was no checking process, or it was not functioning.&lt;&#x2F;li&gt;
&lt;li&gt;No review was performed.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;creating-issues&quot;&gt;Creating Issues&lt;&#x2F;h2&gt;
&lt;p&gt;When creating an issue, create an appropriate issue.&lt;&#x2F;p&gt;
&lt;p&gt;I wrote something similar in &lt;a href=&quot;..&#x2F;best-practice-redmine&#x2F;&quot;&gt;Best Practices for Redmine&lt;&#x2F;a&gt;, but the following points are worth paying attention to.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Create it at an appropriate level of granularity.&lt;&#x2F;li&gt;
&lt;li&gt;Give it an appropriate title.&lt;&#x2F;li&gt;
&lt;li&gt;Write a necessary and sufficient description (overview).&lt;&#x2F;li&gt;
&lt;li&gt;Do not write multiple tasks.&lt;&#x2F;li&gt;
&lt;li&gt;Make the completion conditions clear.&lt;&#x2F;li&gt;
&lt;li&gt;Assign someone to it.&lt;&#x2F;li&gt;
&lt;li&gt;Set a period (an estimated period is also fine).&lt;&#x2F;li&gt;
&lt;li&gt;For bugs, include the necessary information such as reproduction steps, environment (browser used, etc.), version, etc.&lt;br &#x2F;&gt;
* When I was working at a certain foreign-affiliated company, I once saw someone register a bug in the BTS (bug tracking system) without writing this kind of information, and get a reply saying, &lt;strong&gt;&amp;quot;Don&#x27;t write a shitty issue. Rewrite it right away.&amp;quot;&lt;&#x2F;strong&gt; lol.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;From here on, features that are not used very often.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;labels&quot;&gt;Labels&lt;&#x2F;h2&gt;
&lt;p&gt;Labels can be added to issues. Labels can be configured per Project. Using them improves the visibility of issues.&lt;&#x2F;p&gt;
&lt;p&gt;* They are particularly useful when displaying a board (Kanban, described below) or a list of issues.&lt;&#x2F;p&gt;
&lt;p&gt;* The background color can also be configured individually, so if labels are properly configured and used, you can eventually tell what kind of information an issue contains from the label color.&lt;&#x2F;p&gt;
&lt;p&gt;They can be configured from the top icon [&lt;code&gt;Project information&lt;&#x2F;code&gt;] &amp;gt; [&lt;code&gt;Labels&lt;&#x2F;code&gt;] in the project&#x27;s left menu.&lt;&#x2F;p&gt;
&lt;p&gt;I use labels such as the following.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;for-kanban&quot;&gt;For Kanban&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Doing&lt;&#x2F;code&gt;&lt;br &#x2F;&gt;
In progress. Color: #5CB85C&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;To Do&lt;&#x2F;code&gt;&lt;br &#x2F;&gt;
Planned. Color: #F0AD4E&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;close-related&quot;&gt;Close-related&lt;&#x2F;h3&gt;
&lt;p&gt;Used to classify Closed issues. Color: #808080&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Close: Fixed&lt;&#x2F;code&gt;&lt;br &#x2F;&gt;
Fixed &#x2F; addressed.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Close: Wontfix&lt;&#x2F;code&gt;&lt;br &#x2F;&gt;
Will not be addressed.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Close: Duplicate&lt;&#x2F;code&gt;&lt;br &#x2F;&gt;
Duplicate.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Close: Invalid&lt;&#x2F;code&gt;&lt;br &#x2F;&gt;
Incorrect.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Close: Postponed&lt;&#x2F;code&gt;&lt;br &#x2F;&gt;
Postponed.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;priority-related&quot;&gt;Priority-related&lt;&#x2F;h3&gt;
&lt;p&gt;Priority.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Priority: Critical&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Priority: High&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Priority: Middle&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Priority: Low&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The priority labels can be ordered, so I set the label background colors as a gradient.&lt;&#x2F;p&gt;
&lt;p&gt;From Critical onward: #ff0000, #ff4400, #ff8800, #ffbb00&lt;&#x2F;p&gt;
&lt;h3 id=&quot;type-related&quot;&gt;Type-related&lt;&#x2F;h3&gt;
&lt;p&gt;Issue classification. Color: #6699dd&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Type: Bug&lt;&#x2F;code&gt;&lt;br &#x2F;&gt;
Bug.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Type: Documentation&lt;&#x2F;code&gt;&lt;br &#x2F;&gt;
Document&#x2F;documentation creation.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Type: Feature&lt;&#x2F;code&gt;&lt;br &#x2F;&gt;
Feature addition&#x2F;extension.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Type: Refactoring&lt;&#x2F;code&gt;&lt;br &#x2F;&gt;
Refactoring.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Type: Review&lt;&#x2F;code&gt;&lt;br &#x2F;&gt;
Review.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Type: Test&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Even if the issue list or Kanban simply becomes colorful and makes you feel somewhat better (* personal opinion), there seem to be few disadvantages in terms of improving visibility.&lt;&#x2F;p&gt;
&lt;p&gt;Also, when I configured labels, there were members who interpreted this as meaning that every issue must have a label, but that is not the case.&lt;&#x2F;p&gt;
&lt;p&gt;Depending on the type of label, there may be labels that should be mandatory, but it is not necessarily possible for the issue creator to immediately determine things such as the priority.&lt;&#x2F;p&gt;
&lt;p&gt;Once a label has been assigned, it may be interpreted as meaning that it has already been set and that the assigned label is appropriate. Therefore, for things that cannot be determined reliably at the time of issue creation, I think it is better not to assign a label and instead set it during a discussion or similar.&lt;&#x2F;p&gt;
&lt;p&gt;* There is a feature called &lt;a href=&quot;https:&#x2F;&#x2F;docs.gitlab.com&#x2F;ee&#x2F;user&#x2F;project&#x2F;labels.html#scoped-labels&quot;&gt;Scoped labels&lt;&#x2F;a&gt;, and I thought this would be useful, but it was not available in the non-PREMIUM version.&lt;&#x2F;p&gt;
&lt;p&gt;This feature allows labels in &lt;code&gt;key::value&lt;&#x2F;code&gt; format by putting &lt;code&gt;::&lt;&#x2F;code&gt; in the label name. This format would be more convenient when assigning labels such as Priority or Severity.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;reference&quot;&gt;Reference&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.gitlab.com&#x2F;ee&#x2F;user&#x2F;project&#x2F;labels.html&quot;&gt;Labels&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;milestones&quot;&gt;Milestones&lt;&#x2F;h2&gt;
&lt;p&gt;They can be configured&#x2F;used from &lt;code&gt;Issues&lt;&#x2F;code&gt; &amp;gt; &lt;code&gt;Milestones&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I also use milestones in actual work projects to describe what is planned for each release, but it seems to me that there are not many projects around me that set milestones.&lt;&#x2F;p&gt;
&lt;p&gt;Unless it is a contract development project where the work is simply considered finished once it is delivered, it makes the project easier to understand if you record what you are doing in the current development or what you will do up to the next release (the main purpose and major additions).&lt;&#x2F;p&gt;
&lt;p&gt;You do not need to list individual issues in the milestone, but since a milestone can be set on each issue itself, it can also be used for looking back on things such as:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Which milestone was this issue implemented in?&lt;&#x2F;li&gt;
&lt;li&gt;Which issues were addressed in a particular release (Milestone)?&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;It can also be used to indicate that although an issue has been raised, the task will not be performed in the current milestone (the request is acknowledged, but implementation has not been decided).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;reference-1&quot;&gt;Reference&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.gitlab.com&#x2F;ee&#x2F;user&#x2F;project&#x2F;milestones&#x2F;&quot;&gt;Milestones&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;kanban&quot;&gt;Kanban&lt;&#x2F;h2&gt;
&lt;p&gt;It can be used from &lt;code&gt;Issues&lt;&#x2F;code&gt; &amp;gt; &lt;code&gt;Boards&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;GitLab calls this &amp;quot;Boards&amp;quot;, but I think many people are more familiar with the term Kanban.&lt;&#x2F;p&gt;
&lt;p&gt;By default, GitLab provides the following states:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Open&lt;&#x2F;code&gt;&lt;br &#x2F;&gt;
The state when an issue is created.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Closed&lt;&#x2F;code&gt;&lt;br &#x2F;&gt;
Move to &lt;code&gt;Closed&lt;&#x2F;code&gt; when the work is completed.&lt;&#x2F;li&gt;
&lt;li&gt;In addition to the above, labels representing states on the Kanban board can be configured.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Personally, I often managed tasks using a Gantt chart in Redmine, but in some projects I also managed tasks using Kanban based on requests from the customer&#x27;s manager, etc. (For Redmine, I used an Agile plugin.)&lt;&#x2F;p&gt;
&lt;p&gt;We regularly checked tasks with the relevant people on the Kanban board and changed the state of each task.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Everyone can see the general status of the tasks.&lt;&#x2F;li&gt;
&lt;li&gt;By operating it with rules such as moving important tasks higher on the board, the importance&#x2F;priority of tasks can also be visualized.&lt;&#x2F;li&gt;
&lt;li&gt;Since the assignee is also displayed, it is easier to understand how many tasks each person is handling.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Whether it is suitable or not depends on the type and size of the project, the characteristics of the participating members, etc., so it is not something that must always be used. However, if you have never used it, it may be worth trying.&lt;&#x2F;p&gt;
&lt;p&gt;I think it has good compatibility with situations such as:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;quot;It is too small a project to make a Gantt chart...&amp;quot;&lt;&#x2F;li&gt;
&lt;li&gt;When using an agile development methodology.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;reference-2&quot;&gt;Reference&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.gitlab.com&#x2F;ee&#x2F;user&#x2F;project&#x2F;issue_board.html&quot;&gt;Issue boards&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;qiita.com&#x2F;tnir&#x2F;items&#x2F;a488334247f112b083f3&quot;&gt;Trying Kanban and Scrum with GitLab Issue Boards&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;time-management&quot;&gt;Time Management&lt;&#x2F;h2&gt;
&lt;p&gt;By using &lt;code&gt;Time tracking&lt;&#x2F;code&gt; and &lt;code&gt;Due dates&lt;&#x2F;code&gt;, it is possible to manage task time and schedules.&lt;&#x2F;p&gt;
&lt;p&gt;Time management for each task (issue) is important when progressing a project.&lt;&#x2F;p&gt;
&lt;p&gt;Personally, I do not think it is necessary to manage time rigidly for a project that is progressing smoothly without needing time tracking, but if situations such as the following continue:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Progress is not going well.&lt;&#x2F;li&gt;
&lt;li&gt;You do not know how much effort a task will require.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;then it is better to start by making the situation visible.&lt;&#x2F;p&gt;
&lt;p&gt;Problems that are not visible are very often left unresolved &#x2F; not improved, so making them visible is the first step.&lt;&#x2F;p&gt;
&lt;p&gt;GitLab&#x27;s &lt;code&gt;Time tracking&lt;&#x2F;code&gt; and &lt;code&gt;Due dates&lt;&#x2F;code&gt; can be used to manage task time and schedules.&lt;&#x2F;p&gt;
&lt;p&gt;For each issue, you can make the situation visible by recording:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;How long it is expected to take&lt;br &#x2F;&gt;
Estimate: &lt;code&gt;&#x2F;estimate&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;The actual effort spent&lt;br &#x2F;&gt;
&lt;code&gt;&#x2F;spend&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;When it is expected to be completed&lt;br &#x2F;&gt;
&lt;code&gt;Due date&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;estimate&quot;&gt;Estimate&lt;&#x2F;h3&gt;
&lt;p&gt;You can enter an estimated effort by entering something like &lt;code&gt;&#x2F;estimate 1w 2d 5h&lt;&#x2F;code&gt; in an issue comment.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Hints are displayed while entering the command, so use them as a reference.&lt;&#x2F;li&gt;
&lt;li&gt;Note that 1w == 7d is not the case; 1w = 5d.&lt;&#x2F;li&gt;
&lt;li&gt;Obviously, 1d = 24h is not the case either, but I do not think anyone gets this wrong.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;To cancel an estimate, use &lt;code&gt;remove_estimate&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;To change it, enter &lt;code&gt;&#x2F;estimate xxx&lt;&#x2F;code&gt; again. It seems to overwrite the previous value rather than adding to it, so be careful about this as well.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;actual-effort&quot;&gt;Actual Effort&lt;&#x2F;h3&gt;
&lt;p&gt;Enter it using &lt;code&gt;&#x2F;spend xxx&lt;&#x2F;code&gt; in an issue comment. The time format is the same as &lt;code&gt;estimate&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;* With &#x2F;spend, the entered value is added to the existing value (unlike &#x2F;estimate).&lt;&#x2F;p&gt;
&lt;p&gt;If you enter both estimate and spend, a progress bar is displayed in the &lt;code&gt;Time tracking&lt;&#x2F;code&gt; section on the right side of the issue.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;due-date&quot;&gt;Due Date&lt;&#x2F;h3&gt;
&lt;p&gt;The due date can be entered in the &lt;code&gt;Due date&lt;&#x2F;code&gt; field on the right side of the issue.&lt;&#x2F;p&gt;
&lt;p&gt;It is also possible to set it using &lt;code&gt;&#x2F;due xxx&lt;&#x2F;code&gt; in an issue comment, but examples of the format for the xxx part include &lt;code&gt;in 2 days&lt;&#x2F;code&gt;, &lt;code&gt;this Friday&lt;&#x2F;code&gt;, and &lt;code&gt;December 31st&lt;&#x2F;code&gt;, which may be unfamiliar to Japanese users. I recommend setting it using the calendar in the Due date field.&lt;&#x2F;p&gt;
&lt;p&gt;Issues that are past their due date are displayed with a different color, and their display in the &lt;code&gt;To-Do List&lt;&#x2F;code&gt; (accessible from the icon in the upper-right of GitLab) also changes.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;reference-3&quot;&gt;Reference&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.gitlab.com&#x2F;ee&#x2F;user&#x2F;project&#x2F;time_tracking.html&quot;&gt;Time tracking&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.gitlab.com&#x2F;ee&#x2F;user&#x2F;project&#x2F;issues&#x2F;due_dates.html&quot;&gt;Due dates&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;gantt-chart&quot;&gt;Gantt Chart&lt;&#x2F;h3&gt;
&lt;p&gt;Apparently, this can be done with the &lt;a href=&quot;https:&#x2F;&#x2F;docs.gitlab.com&#x2F;user&#x2F;group&#x2F;roadmap&#x2F;&quot;&gt;Roadmap&lt;&#x2F;a&gt; feature with Premium or Ultimate.&lt;&#x2F;p&gt;
&lt;p&gt;I have used https:&#x2F;&#x2F;github.com&#x2F;lamact&#x2F;react-issue-ganttchart to display a Gantt chart based on Due dates. If you want to use a Gantt chart with CE or similar, you may want to try it.&lt;&#x2F;p&gt;
&lt;p&gt;* This is not a GitLab feature itself.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;mr-draft-feature-formerly-wip&quot;&gt;MR Draft Feature (formerly WIP)&lt;&#x2F;h2&gt;
&lt;p&gt;Below the MR Title input field, there is a message saying &lt;code&gt;Start the title with Draft: to prevent a merge request that is a work in progress from being merged before it&#x27;s ready.&lt;&#x2F;code&gt;. By clicking the &lt;code&gt;Start the title with Draft:&lt;&#x2F;code&gt; link, you can indicate that this MR is in a draft state.&lt;&#x2F;p&gt;
&lt;p&gt;This feature was formerly called WIP (Work In Progress), and an MR created in Draft state is created with the merge button disabled.&lt;&#x2F;p&gt;
&lt;p&gt;When work is still in progress and not yet complete, but you want reviews or comments (a draft state), you should use the MR Draft feature.&lt;&#x2F;p&gt;
&lt;p&gt;If you manage documents on GitLab and want members to comment or check them, I think this can also be useful.&lt;&#x2F;p&gt;
&lt;p&gt;An MR created in Draft state can also be changed to a non-Draft state using the &lt;code&gt;Mark as ready&lt;&#x2F;code&gt; button after reflecting the review comments. (It can also be returned to Draft state again.)&lt;&#x2F;p&gt;
&lt;h3 id=&quot;reference-4&quot;&gt;Reference&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.gitlab.com&#x2F;ee&#x2F;user&#x2F;project&#x2F;merge_requests&#x2F;drafts.html&quot;&gt;Draft merge requests&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;problems-that-still-occurred&quot;&gt;Problems That Still Occurred&lt;&#x2F;h2&gt;
&lt;p&gt;Even if you establish rules such as the above, problems can still occur.&lt;&#x2F;p&gt;
&lt;p&gt;Here are some specific examples.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;what-is-this-issue-supposed-to-do&quot;&gt;What Is This Issue Supposed to Do?&lt;&#x2F;h3&gt;
&lt;p&gt;An issue was created with only a title, or with an insufficient overview, and it ended up in a &amp;quot;What is this supposed to do?&amp;quot; state.&lt;&#x2F;p&gt;
&lt;p&gt;The flow was something like this:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Member B&lt;&#x2F;strong&gt;: &amp;quot;There is a problem with XX regarding OO, so we should address it.&amp;quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Member A&lt;&#x2F;strong&gt;: &amp;quot;I&#x27;ll handle it.&amp;quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Member B&lt;&#x2F;strong&gt;: &amp;quot;Please write an issue.&amp;quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Member A&lt;&#x2F;strong&gt;: &amp;quot;Understood.&amp;quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Member A&lt;&#x2F;strong&gt;: Creates an issue (title only).&lt;br &#x2F;&gt;
The title itself was something like &lt;code&gt;Decide OO&lt;&#x2F;code&gt;, which leaves you wondering, &amp;quot;Decide what?&amp;quot;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;The issue then remained untouched for some time (for reasons such as other tasks having higher priority).&lt;&#x2F;p&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;&lt;strong&gt;Member A&lt;&#x2F;strong&gt;: Closes the issue because there was &amp;quot;nothing that needed to be decided.&amp;quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Member B&lt;&#x2F;strong&gt;: Comments that the problem has not been resolved.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Member A&lt;&#x2F;strong&gt;: Admits that they do not remember anymore.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;This problem can be avoided if the issue contains the necessary and sufficient information.&lt;&#x2F;p&gt;
&lt;p&gt;* The same problem may occur repeatedly (based on experience).&lt;&#x2F;p&gt;
&lt;p&gt;* If it keeps happening, it is best to have the members themselves come up with countermeasures, but if that is not possible, &lt;a href=&quot;https:&#x2F;&#x2F;qiita.com&#x2F;e99h2121&#x2F;items&#x2F;2690103fce58cdbdc714&quot;&gt;prepare an issue template&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;branch-name-does-not-follow-the-naming-convention&quot;&gt;Branch Name Does Not Follow the Naming Convention&lt;&#x2F;h3&gt;
&lt;p&gt;Follow the naming rules.&lt;&#x2F;p&gt;
&lt;p&gt;When pushing a new branch to GitLab, I recommend checking things such as:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Is the branch name appropriate?&lt;&#x2F;li&gt;
&lt;li&gt;What do the existing branches look like?&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;problems-with-the-branch-creation-procedure-probably&quot;&gt;Problems with the Branch Creation Procedure (Probably)&lt;&#x2F;h3&gt;
&lt;p&gt;There was once a problem where an MR included changes that had already been merged.&lt;&#x2F;p&gt;
&lt;p&gt;When creating the feature branch, it seems that the branch was probably created not from the latest develop, but from a local develop that had not been updated to the latest state.&lt;&#x2F;p&gt;
&lt;p&gt;Even if someone accidentally proceeded to create the MR as-is, if they checked the differences before creating the MR (which can be checked on GitLab), they should have noticed that the branch contained changes they had not made in that feature branch.&lt;&#x2F;p&gt;
&lt;p&gt;The reasons for this problem included the following two things:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The branch creation rules were inadequate.&lt;&#x2F;li&gt;
&lt;li&gt;There was no review at the time of the MR.&lt;br &#x2F;&gt;
Even when there is no reviewer, you still need to check whether the differences included in the MR are appropriate. In the case of self-review, check them properly yourself.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;I really think you should stop using overly lax permission settings.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Oracle User Management Best Practices</title>
        <published>2026-09-22T00:00:00+00:00</published>
        <updated>2026-09-22T00:00:00+00:00</updated>
        <author>
          <name>Unknown</name>
        </author>
        <link rel="alternate" href="https://mosaos.github.io/blog/best-practice-oracle-usermgmt/" type="text/html"/>
        <id>https://mosaos.github.io/blog/best-practice-oracle-usermgmt/</id>
        
        <content type="html">&lt;h1 id=&quot;oracle-user-management-best-practices&quot;&gt;Oracle User Management Best Practices&lt;&#x2F;h1&gt;
&lt;p&gt;My personal best-practice series lol.&lt;&#x2F;p&gt;
&lt;p&gt;I will not cover things used individually, such as development environments, here.
This is specifically about best practices for production environments (and staging environments shared by multiple people).&lt;&#x2F;p&gt;
&lt;p&gt;* I am not an Oracle master, so this may contain incorrect information. Please keep that in mind.&lt;br &#x2F;&gt;
* I am writing down some best-practice-like guidelines on how access users should be managed for databases in production environments.&lt;br &#x2F;&gt;
* These ideas may also apply to permission management for applications and operating systems, not just databases.&lt;br &#x2F;&gt;
* This topic was written in the heat of the moment when someone messed something up...&lt;&#x2F;p&gt;
&lt;p&gt;* This is a rewrite of an old article, so some parts may differ from the current Oracle specifications or UI.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;terminology&quot;&gt;Terminology&lt;&#x2F;h2&gt;
&lt;p&gt;Let me define a few terms first.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;DBA&lt;br &#x2F;&gt;
Short for Database Administrator. A database administrator. A person&#x2F;account that can do anything to the database (has all privileges).&lt;&#x2F;li&gt;
&lt;li&gt;Default user&lt;br &#x2F;&gt;
&lt;a href=&quot;https:&#x2F;&#x2F;mosaos.github.io&#x2F;blog&#x2F;best-practice-oracle-usermgmt&#x2F;h%5Bttps:&#x2F;&#x2F;blogs.oracle.com&#x2F;sec&#x2F;post&#x2F;021_users_by_default%5D(https:&#x2F;&#x2F;blogs.oracle.com&#x2F;sec&#x2F;021-users-by-default)&quot;&gt;[第21回] Users created by default from the beginning&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Production environment&lt;br &#x2F;&gt;
The production&#x2F;operational environment.&lt;&#x2F;li&gt;
&lt;li&gt;Staging environment&lt;br &#x2F;&gt;
An environment used for verification, etc. It is used for pre-production verification and testing. Unlike individual developers&#x27; development environments, it is shared by multiple people.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;best-practices&quot;&gt;Best Practices&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;grant-privileges-to-roles-not-users&quot;&gt;Grant privileges to roles, not users&lt;&#x2F;h3&gt;
&lt;p&gt;Oracle provides a mechanism for handling roles (ROLE), so instead of granting privileges to individual users, assign privileges to roles and configure individual users to belong to those roles.&lt;&#x2F;p&gt;
&lt;p&gt;Reference: &lt;a href=&quot;https:&#x2F;&#x2F;atmarkit.itmedia.co.jp&#x2F;fdb&#x2F;ref&#x2F;ref_oracle&#x2F;role.html&quot;&gt;Checking &#x2F; Creating &#x2F; Granting &#x2F; Changing &#x2F; Revoking &#x2F; Deleting Roles&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;give-users-the-minimum-access-privileges-they-need&quot;&gt;Give users the minimum access privileges they need.&lt;&#x2F;h3&gt;
&lt;p&gt;When you want to make management less restrictive, you may be tempted to give users many privileges, but this can introduce security risks.&lt;br &#x2F;&gt;
For important systems, give users only the minimum privileges they need to perform their work.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;perform-auditing&quot;&gt;Perform auditing&lt;&#x2F;h3&gt;
&lt;p&gt;Oracle provides mechanisms for auditing login attempts and operations.&lt;br &#x2F;&gt;
If auditing is disabled, enable it so that sufficient auditing can be performed.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;lock-default-users-whenever-possible&quot;&gt;Lock default users whenever possible.&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blogs.oracle.com&#x2F;sec&#x2F;021-users-by-default&quot;&gt;[第21回] Users created by default from the beginning&lt;&#x2F;a&gt; are among the easiest accounts for attackers to target, so it is preferable to lock them whenever possible.&lt;br &#x2F;&gt;
For accounts that cannot be locked, set sufficiently strong passwords.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;do-not-make-default-users-dbas&quot;&gt;Do not make default users DBAs&lt;&#x2F;h3&gt;
&lt;p&gt;It is easy to make default users such as SYS&#x2F;SYSTEM DBA users, but instead, create individual DBA users for the people who perform DBA operations. There are the following reasons.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Auditing&lt;br &#x2F;&gt;
When a shared privileged account is used, it is troublesome to audit and track which user performed a DBA operation. Auditing is easier when individual users are provided.&lt;&#x2F;li&gt;
&lt;li&gt;Password management&lt;br &#x2F;&gt;
Even for DBA users, by ensuring that each person does not know anyone else&#x27;s password, password management becomes easier when someone leaves the company. This is also effective from a security and auditing perspective.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;separate-dba-and-developer-roles&quot;&gt;Separate DBA and developer roles&lt;&#x2F;h3&gt;
&lt;p&gt;During application development, especially in development environments, the DBA and developer are often the same person.&lt;br &#x2F;&gt;
However, in production environments, DBAs and developers are usually separate.&lt;br &#x2F;&gt;
Create different roles for these two roles (jobs) and assign privileges separately.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;eliminate-anonymity-for-application-dba-users&quot;&gt;Eliminate anonymity for application&#x2F;DBA users&lt;&#x2F;h3&gt;
&lt;p&gt;The user used by an application may inevitably become a shared&#x2F;representative user.&lt;br &#x2F;&gt;
Application representative users often have powerful privileges, and even if the account information is leaked, it may be difficult to change the password.&lt;br &#x2F;&gt;
However, even after an operations staff member leaves the company, they may still be able to access the system using a password they used in the past.&lt;br &#x2F;&gt;
For applications that directly access the database and for personnel responsible for database administration and operations, it is preferable to create individual accounts in order to eliminate anonymity and enforce strict access control.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;nest-roles&quot;&gt;Nest roles&lt;&#x2F;h3&gt;
&lt;p&gt;Oracle roles can be nested.&lt;br &#x2F;&gt;
I have never configured this personally, but I have seen setups such as the following:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;DEVELOPER&lt;&#x2F;code&gt; role for developers&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;MAINTAINER&lt;&#x2F;code&gt; role for database maintenance personnel&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;MANAGER&lt;&#x2F;code&gt; role with both &lt;code&gt;DEVELOPER&lt;&#x2F;code&gt; and &lt;code&gt;MAINTAINER&lt;&#x2F;code&gt; privileges&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;When the privileges of &lt;code&gt;DEVELOPER&lt;&#x2F;code&gt; are updated, the &lt;code&gt;MANAGER&lt;&#x2F;code&gt; role is also updated.&lt;br &#x2F;&gt;
When there are users whose jobs involve multiple tasks, nesting roles may make management more flexible and reduce management costs.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;do-not-use-the-connect-resource-roles&quot;&gt;Do not use the CONNECT&#x2F;RESOURCE roles.&lt;&#x2F;h3&gt;
&lt;p&gt;Some roles such as CONNECT are built into Oracle, but these roles should not be used.&lt;br &#x2F;&gt;
Since 10g R2, the CONNECT and RESOURCE roles have been deprecated based on the principle of least privilege.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nkurilog.blogspot.com&#x2F;2018&#x2F;02&#x2F;oracle-connectresource.html&quot;&gt;Overview of Oracle CONNECT and RESOURCE Roles&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;※ The privileges included in these roles seem to differ depending on the version, so using them without understanding them can be dangerous.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;be-careful-with-public&quot;&gt;Be careful with PUBLIC&lt;&#x2F;h3&gt;
&lt;p&gt;When privileges are granted to PUBLIC, anyone can use those privileges.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blogs.oracle.com&#x2F;sec&#x2F;post&#x2F;022_public_role&quot;&gt;[第22回] Be careful with PUBLIC&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;determine-roles-based-on-use-cases&quot;&gt;Determine roles based on use cases&lt;&#x2F;h3&gt;
&lt;p&gt;Consider the following based on actual operations.&lt;br &#x2F;&gt;
As much as possible, create and visualize an access matrix or something similar to organize the privileges.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Users&lt;br &#x2F;&gt;
Who are the users that access the database? What types of users are there?&lt;&#x2F;li&gt;
&lt;li&gt;Privileges&lt;br &#x2F;&gt;
What privileges are required for each type of user (actor)?&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;When a system is still in development, it may be difficult to decide everything, but define users and roles as much as possible.&lt;br &#x2F;&gt;
Review them at appropriate intervals, such as when adding a new application or a new feature.&lt;&#x2F;p&gt;
&lt;p&gt;When a problem occurs, it is also a good opportunity to review them.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;references&quot;&gt;References&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blogs.oracle.com&#x2F;sec&#x2F;021-users-by-default&quot;&gt;[第21回] Users created by default from the beginning&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blogs.oracle.com&#x2F;sec&#x2F;post&#x2F;022_public_role&quot;&gt;[第22回] Be careful with PUBLIC&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nkurilog.blogspot.com&#x2F;2018&#x2F;02&#x2F;oracle-connectresource.html&quot;&gt;Overview of Oracle CONNECT and RESOURCE Roles&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;atmarkit.itmedia.co.jp&#x2F;fdb&#x2F;ref&#x2F;ref_oracle&#x2F;role.html&quot;&gt;Checking &#x2F; Creating &#x2F; Granting &#x2F; Changing &#x2F; Revoking &#x2F; Deleting Roles&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;atmarkit.itmedia.co.jp&#x2F;ait&#x2F;articles&#x2F;1803&#x2F;13&#x2F;news008.html&quot;&gt;The Key to Secure Database Operations: How Should User Access Control Be Configured?&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Redmine Best Practices</title>
        <published>2026-09-22T00:00:00+00:00</published>
        <updated>2026-09-22T00:00:00+00:00</updated>
        <author>
          <name>Unknown</name>
        </author>
        <link rel="alternate" href="https://mosaos.github.io/blog/best-practice-redmine/" type="text/html"/>
        <id>https://mosaos.github.io/blog/best-practice-redmine/</id>
        
        <content type="html">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;This is not a manual-style explanation of how to use Redmine.&lt;br &#x2F;&gt;
Instead, I will write about the following points when using Redmine (or similar project management tools):&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Things you should pay attention to&lt;&#x2F;li&gt;
&lt;li&gt;Things you should stop doing (bad practices)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;* This also includes things I have heard on Redmine Japan.&lt;br &#x2F;&gt;
* I think these ideas are also useful when using project management tools other than Redmine.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;what-is-redmine&quot;&gt;What is Redmine?&lt;&#x2F;h2&gt;
&lt;p&gt;Redmine originally started as a tool for IT developers, but today it is a &lt;strong&gt;project management tool&lt;&#x2F;strong&gt; used in various fields and types of work.&lt;&#x2F;p&gt;
&lt;p&gt;When someone asks me, &amp;quot;What is a project management tool?&amp;quot;, I explain it as something that allows you to:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;&amp;quot;Write down things you need to do on sticky notes, and remove them when they are done&amp;quot;&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;with the help of IT, and&lt;&#x2F;li&gt;
&lt;li&gt;in a more systematic way.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The sticky notes are Redmine tickets, so it basically means:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Write what needs to be done in a ticket.&lt;&#x2F;li&gt;
&lt;li&gt;Remove it when it is done.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;remove-tickets&quot;&gt;Remove tickets&lt;&#x2F;h3&gt;
&lt;p&gt;So, if I had to give one purpose of using Redmine, it would be:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;&amp;quot;Write tickets and remove them.&amp;quot;&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;* If you can make removing tickets feel good through gamification, it becomes easier for people to keep using the tool.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Remove your own tickets&lt;&#x2F;li&gt;
&lt;li&gt;Remove other members&#x27; tickets too&lt;&#x2F;li&gt;
&lt;li&gt;Keep records&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;At the same time, properly record the actions taken to complete the tickets.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;to-make-tickets-removable&quot;&gt;To make tickets removable&lt;&#x2F;h4&gt;
&lt;p&gt;If the number of tickets that cannot be completed keeps increasing, people&#x27;s motivation will not improve, and use of the tool will not be encouraged.
To make tickets easier to complete, pay attention to the following:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Create tickets at a manageable level of granularity
Tickets that cover too wide a scope (are too large in granularity) cannot be easily completed.&lt;br &#x2F;&gt;
→ Split them into child tickets (create them at a granularity that can generally be completed in a few hours to a few days).&lt;&#x2F;li&gt;
&lt;li&gt;Do not write multiple tasks in one ticket
Even when leaving records (comments), it becomes difficult to tell which task the work was for.&lt;br &#x2F;&gt;
→ As above, split them into child tickets with an appropriate level of granularity.&lt;&#x2F;li&gt;
&lt;li&gt;Create tickets with clear completion conditions
With a ticket such as &amp;quot;Improve operations&amp;quot;, it is unclear what needs to be done before it can be completed.&lt;br &#x2F;&gt;
→ Create tickets that describe the actual actions that need to be performed, such as &amp;quot;Do XX to YY&amp;quot;, and make the completion conditions clear.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;visualization&quot;&gt;Visualization&lt;&#x2F;h3&gt;
&lt;p&gt;Keeping records makes visualization possible. Visualization is important.&lt;br &#x2F;&gt;
Be conscious of what you want to &#x2F; should visualize. If this becomes unclear, you may end up with unnecessary information or fail to capture what you actually wanted to visualize.&lt;&#x2F;p&gt;
&lt;p&gt;This depends on the project, so it is difficult to say &amp;quot;this is the answer.&amp;quot; Here are some examples.&lt;&#x2F;p&gt;
&lt;p&gt;The following is an example for a development project.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Things to do (or things that should be done)&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Write them in tickets (pay attention to granularity)&lt;&#x2F;li&gt;
&lt;li&gt;Assign someone responsible (if undecided, assign it to the project manager or whoever is responsible for making assignments)&lt;&#x2F;li&gt;
&lt;li&gt;Set a period (a tentative period is also fine)&lt;&#x2F;li&gt;
&lt;li&gt;Give it an appropriate title&lt;&#x2F;li&gt;
&lt;li&gt;Write a sufficient description (overview)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Schedule&lt;br &#x2F;&gt;
By recording the period and progress percentage in tickets, they can be visualized as a Gantt chart.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Task status&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Properly write the work being done in comments. Change the status and assignee as appropriate.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;things-to-pay-attention-to-when-operating&quot;&gt;Things to Pay Attention to When Operating&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Do not divide settings too finely&lt;br &#x2F;&gt;
When operating Redmine, it is tempting to divide various settings into many detailed categories.&lt;br &#x2F;&gt;
However, the more finely you divide them, the more the cost of configuration, operation, and maintenance increases.
I recommend not dividing them more than necessary.&lt;&#x2F;li&gt;
&lt;li&gt;Basically, do not directly reflect the organizational structure&lt;br &#x2F;&gt;
It may be fairly common to structure the data based on actual departments and positions at the beginning, but doing this will often fail or make management difficult.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;A project management tool is not a tool for managing the organizational or job-position structure within a project. It is ultimately a tool for handling tasks.&lt;br &#x2F;&gt;
I recommend defining only the minimum necessary and efficient trackers, statuses, roles, and projects needed for the purpose.&lt;br &#x2F;&gt;
Start with the minimum and change&#x2F;improve things as necessary.&lt;&#x2F;p&gt;
&lt;p&gt;The following are some specific examples of bad practices.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;do-not-create-too-many-trackers&quot;&gt;Do not create too many trackers&lt;&#x2F;h3&gt;
&lt;p&gt;A tracker is a category for tickets, so let&#x27;s create a separate tracker for each type of work.&lt;br &#x2F;&gt;
→ &lt;strong&gt;&amp;quot;Let&#x27;s create separate ones for each type of work&#x2F;department!&amp;quot;&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This is fairly common.&lt;&#x2F;p&gt;
&lt;p&gt;* &lt;strong&gt;A Redmine tracker has the characteristics of a form&lt;&#x2F;strong&gt; (it has input fields and an approval workflow).&lt;&#x2F;p&gt;
&lt;p&gt;But often,&lt;&#x2F;p&gt;
&lt;p&gt;you create many trackers, only to find that they actually have the same workflow.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;If the input fields and workflow are the same, there is a high possibility that the same tracker can be used.&lt;&#x2F;li&gt;
&lt;li&gt;The more settings there are, the higher the management and maintenance costs become.&lt;&#x2F;li&gt;
&lt;li&gt;It becomes painful when you try to organize them later.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;too-many-input-fields&quot;&gt;Too many input fields&lt;&#x2F;h3&gt;
&lt;p&gt;I said that a tracker is like a form, but&lt;br &#x2F;&gt;
it is also easy to end up with a situation where you keep adding custom fields until you no longer know what needs to be entered.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;There are fields that are ultimately not filled in.&lt;&#x2F;li&gt;
&lt;li&gt;There are fields that have become merely nominal and are not actually being used.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Unless you plan to use the information later for analysis or aggregation, it is often sufficient to simply write it in the ticket description field.&lt;&#x2F;p&gt;
&lt;p&gt;If there are items you want people to enter (but do not need to analyze), use the Issue Templates plugin.&lt;br &#x2F;&gt;
→ This also helps prevent a proliferation of trackers.&lt;&#x2F;p&gt;
&lt;p&gt;* Apparently, some systems actually have around 100 input fields... hell.&lt;br &#x2F;&gt;
* I have seen trackers with both an assignee and a person responsible for handling the ticket. What is the difference?&lt;&#x2F;p&gt;
&lt;h3 id=&quot;keep-statuses-to-the-minimum-necessary&quot;&gt;Keep statuses to the minimum necessary&lt;&#x2F;h3&gt;
&lt;p&gt;Making them more detailed than necessary makes things difficult to understand.&lt;br &#x2F;&gt;
→ A good state is one where someone who has just joined the project can understand which status to select.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Have you organized the actual workflow?&lt;br &#x2F;&gt;
Some statuses exist in actual business operations but are unnecessary in the system.&lt;br &#x2F;&gt;
Stop creating statuses when it is unclear whether they are really necessary.&lt;br &#x2F;&gt;
You can always add one when it actually becomes necessary.&lt;&#x2F;li&gt;
&lt;li&gt;Do you really need a status where no assignee can be assigned?&lt;br &#x2F;&gt;
→ This makes it more likely that tickets will not be completed.&lt;&#x2F;li&gt;
&lt;li&gt;If there are multiple statuses that occupy the same position in the workflow (for example, separate ones created for different departments), consolidate them.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;* Apparently, some systems actually have around 30 statuses... Can you really understand and keep track of that workflow?&lt;br &#x2F;&gt;
* Redmine can also be used as a Kanban board by adding a plugin, but a Kanban board with 30 statuses would be chaos...&lt;&#x2F;p&gt;
&lt;h3 id=&quot;stop-subdividing-roles-too-much&quot;&gt;Stop subdividing roles too much&lt;&#x2F;h3&gt;
&lt;p&gt;&amp;quot;It is not good for too many people to be able to see things. Let&#x27;s use roles to divide permissions in detail.&amp;quot;&lt;br &#x2F;&gt;
→ I have seen places where roles are created for each job position...&lt;&#x2F;p&gt;
&lt;p&gt;PM? PMO? PL? What can each role actually do in Redmine?&lt;br &#x2F;&gt;
→ Roles with clearly defined responsibilities, such as approver, reviewer, and observer, are better.&lt;&#x2F;p&gt;
&lt;p&gt;* You do not need to create roles based on job positions, such as &amp;quot;these permissions because they are a PM&amp;quot; or &amp;quot;these permissions because they are a PL.&amp;quot;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;what-about-workflows&quot;&gt;What about workflows?&lt;&#x2F;h3&gt;
&lt;p&gt;There is one workflow for each combination of role × tracker.&lt;&#x2F;p&gt;
&lt;p&gt;The more there are, the harder they are to manage.&lt;&#x2F;p&gt;
&lt;p&gt;For workflows that are the same, try to handle them with the same tracker whenever possible.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Task (no approval required)&lt;&#x2F;li&gt;
&lt;li&gt;Customer approval task&lt;&#x2F;li&gt;
&lt;li&gt;Manager approval task&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;If the workflows are the same, such trackers should be consolidated so that the same tracker can be used even when work crosses departments. This makes things easier to understand.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;do-not-unnecessarily-subdivide-projects&quot;&gt;Do not unnecessarily subdivide projects&lt;&#x2F;h3&gt;
&lt;p&gt;It is common to have &amp;quot;one project per case&amp;quot;...&lt;&#x2F;p&gt;
&lt;p&gt;If using &amp;quot;Versions&amp;quot; is sufficient, use Versions.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Redmine also makes it easy to integrate with source code.&lt;br &#x2F;&gt;
→ By using appropriate plugins together, it is possible to configure a Subversion&#x2F;Git repository server on the Redmine server.&lt;br &#x2F;&gt;
→ I recommend associating one product&#x2F;service with one project.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;If you have a project such as &amp;quot;XX Service - YY Improvement&amp;quot;, you can create a &amp;quot;YY Improvement&amp;quot; version in the &amp;quot;XX Service&amp;quot; project. This allows you to divide the roadmap for each product&#x2F;service as needed.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;GitLab Milestones work in a similar way.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;structuring-by-organizational-hierarchy-is-a-bad-idea&quot;&gt;Structuring by organizational hierarchy is a bad idea&lt;&#x2F;h3&gt;
&lt;p&gt;This is common.&lt;&#x2F;p&gt;
&lt;p&gt;But what if a project needs to be carried out collaboratively by multiple departments?&lt;&#x2F;p&gt;
&lt;p&gt;→ I recommend structuring projects by case.&lt;br &#x2F;&gt;
However, if the phases are different, consider whether the problem can be solved by using Versions instead of unnecessarily splitting the project.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;how-should-versions-be-used&quot;&gt;How should Versions be used?&lt;&#x2F;h3&gt;
&lt;p&gt;Basically, I use Versions to divide a project by period.&lt;&#x2F;p&gt;
&lt;p&gt;It seems that some people use them to divide projects along axes other than time, but&lt;&#x2F;p&gt;
&lt;p&gt;if you later need to divide something by time, you will no longer be able to divide it appropriately. Therefore, do not use this approach except for projects where such a requirement will definitely never occur.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;adding-too-many-members&quot;&gt;Adding too many members&lt;&#x2F;h3&gt;
&lt;p&gt;Was it too much trouble to think about? There are way too many members, aren&#x27;t there?&lt;&#x2F;p&gt;
&lt;p&gt;Basically, only add people who are actually involved in the project as members.&lt;&#x2F;p&gt;
&lt;p&gt;Want to let someone view it only?&lt;br &#x2F;&gt;
→ If a public project is sufficient, that is enough.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;Especially when starting operations, when adding trackers, statuses, or roles, you may sometimes think:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;&amp;quot;I added all these fields! It&#x27;s perfectly structured to match our company, and the workflows are reflected too. Awesome!&amp;quot;&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;But you may simply have failed to analyze or abstract the actual business processes.&lt;&#x2F;p&gt;
&lt;p&gt;Think about ways to make things work well with fewer settings.&lt;&#x2F;p&gt;
&lt;p&gt;Having detailed settings and properly abstracting business processes are two different things.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Coding Rules (Java)</title>
        <published>2026-09-22T00:00:00+00:00</published>
        <updated>2026-09-22T00:00:00+00:00</updated>
        <author>
          <name>Unknown</name>
        </author>
        <link rel="alternate" href="https://mosaos.github.io/blog/java-coding-rule/" type="text/html"/>
        <id>https://mosaos.github.io/blog/java-coding-rule/</id>
        
        <content type="html">&lt;p&gt;Personal coding rules I have compiled through Java development.
&lt;em&gt;These rules also reflect experience in product development in corporate environments.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;One indicator of whether code is good or not is whether it is &amp;quot;easy for other people to understand.&amp;quot;
Whether code is easy to understand is determined by various factors, including not only the clarity of the logic, but also formatting and the conventional use of APIs.&lt;br &#x2F;&gt;
When coding in a project consisting of multiple people, it is necessary to be conscious of whether the code is easy for others to understand as well.&lt;&#x2F;p&gt;
&lt;p&gt;Prioritizing readability is also beneficial for myself when I need to maintain code that I may not have touched for a long time.&lt;&#x2F;p&gt;
&lt;p&gt;This document describes coding rules and recommendations for application development projects using Java as the development language.&lt;&#x2F;p&gt;
&lt;p&gt;This does not mean that &amp;quot;you only need to pay attention to what is written here.&amp;quot; Please code flexibly while keeping in mind the perspective of writing code that is easy to understand.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;This document was created as a draft, so it is intended for reference only. It is recommended that the rules be modified as appropriate for each project and its users.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;files&quot;&gt;Files&lt;&#x2F;h2&gt;
&lt;p&gt;Each public class should be placed in a file named after that class.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Do not write multiple public classes in a single file.&lt;&#x2F;li&gt;
&lt;li&gt;A non-public class that is not used by other classes may be included in the file of the public class that uses it (as an inner class). However, inner classes should not be used in principle.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The file encoding should be UTF-8.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;file-hierarchy&quot;&gt;File Hierarchy&lt;&#x2F;h2&gt;
&lt;p&gt;Follow Maven&#x27;s standard directory layout.&lt;&#x2F;p&gt;
&lt;p&gt;Maven has been used as a de facto standard build tool for Java for a long time, and using Maven&#x27;s standard directory layout makes the project structure easy for many Java developers to understand.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;naming-conventions&quot;&gt;Naming Conventions&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;uppercase-and-lowercase&quot;&gt;Uppercase and Lowercase&lt;&#x2F;h3&gt;
&lt;p&gt;Java is case-sensitive, but do not write code that distinguishes identifiers solely by differences in uppercase and lowercase letters.&lt;&#x2F;p&gt;
&lt;p&gt;Bad example)&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;java&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-java &quot;&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;private int&lt;&#x2F;span&gt;&lt;span&gt; num;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;private int &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;Num&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Good example)&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;java&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-java &quot;&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;private int&lt;&#x2F;span&gt;&lt;span&gt; cartNumber;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;private int&lt;&#x2F;span&gt;&lt;span&gt; productNumber;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;package-names&quot;&gt;Package Names&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;Use strings consisting of lowercase English letters separated by &amp;quot;.&amp;quot; and include a name representing the application&#x2F;project.&lt;&#x2F;li&gt;
&lt;li&gt;If the application is intended to be publicly released, basically include the domain name.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Example) &lt;code&gt;com.mosaos.projectname&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;class-names&quot;&gt;Class Names&lt;&#x2F;h3&gt;
&lt;p&gt;Use UpperCamelCase.&lt;&#x2F;p&gt;
&lt;p&gt;Example) &lt;code&gt;UpperCamelCase&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;exception-class-names&quot;&gt;Exception Class Names&lt;&#x2F;h3&gt;
&lt;p&gt;Use a class name ending in &lt;code&gt;Exception&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;interface-names&quot;&gt;Interface Names&lt;&#x2F;h3&gt;
&lt;p&gt;Follow the same naming convention as class names.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;implementation-class-names&quot;&gt;Implementation Class Names&lt;&#x2F;h3&gt;
&lt;p&gt;If it is necessary to distinguish an implementation class from its interface, append &lt;code&gt;Impl&lt;&#x2F;code&gt; to the end.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;abstract-class-names&quot;&gt;Abstract Class Names&lt;&#x2F;h3&gt;
&lt;p&gt;If there is no suitable name, start with &lt;code&gt;Abstract&lt;&#x2F;code&gt; and use a name that suggests the subclasses.&lt;&#x2F;p&gt;
&lt;p&gt;Do not create abstract classes unnecessarily.&lt;&#x2F;p&gt;
&lt;p&gt;Consider carefully whether an abstract class is really necessary, except when there is a clear purpose such as the Template pattern.&lt;&#x2F;p&gt;
&lt;p&gt;Avoid creating abstract classes (using inheritance) for reasons such as the following:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Inheritance for sharing methods&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;It becomes difficult to modify or add functionality to common methods.&lt;&#x2F;li&gt;
&lt;li&gt;Common methods keep being added to the base class, eventually creating a God class.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Inheritance for sharing member variables&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Member variables become difficult to modify because doing so affects derived classes.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;constants-static-final&quot;&gt;Constants (&lt;code&gt;static final&lt;&#x2F;code&gt;)&lt;&#x2F;h3&gt;
&lt;p&gt;Use uppercase snake case.&lt;&#x2F;p&gt;
&lt;p&gt;Example) &lt;code&gt;UPPER_SNAKE_CASE&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;method-names&quot;&gt;Method Names&lt;&#x2F;h3&gt;
&lt;p&gt;Use lowerCamelCase.&lt;&#x2F;p&gt;
&lt;p&gt;Example) &lt;code&gt;lowerCamelCase&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;For methods that perform an operation, use a name in the form of &lt;strong&gt;verb + object&lt;&#x2F;strong&gt;, rather than &lt;strong&gt;object + verb&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Bad example) &lt;code&gt;couponGet&lt;&#x2F;code&gt;&lt;br &#x2F;&gt;
Good example) &lt;code&gt;getCoupon&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;h4 id=&quot;attribute-access&quot;&gt;Attribute Access&lt;&#x2F;h4&gt;
&lt;p&gt;For methods that retrieve attributes, use the &lt;code&gt;getXxx&lt;&#x2F;code&gt; or &lt;code&gt;isXxx&lt;&#x2F;code&gt; form (&lt;code&gt;xxx&lt;&#x2F;code&gt; is the attribute name).&lt;&#x2F;p&gt;
&lt;h4 id=&quot;attribute-setting&quot;&gt;Attribute Setting&lt;&#x2F;h4&gt;
&lt;p&gt;For methods that set attributes, use the &lt;code&gt;setXxx&lt;&#x2F;code&gt; form (&lt;code&gt;xxx&lt;&#x2F;code&gt; is the attribute name).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;english-and-japanese&quot;&gt;English and Japanese&lt;&#x2F;h3&gt;
&lt;p&gt;Use English as the basic language for all identifiers. In exceptional cases where translating a term into English is difficult, romanized Japanese may also be used. However, whenever possible, create and maintain a terminology dictionary and avoid using different names for the same term.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;naming-symmetry&quot;&gt;Naming Symmetry&lt;&#x2F;h3&gt;
&lt;p&gt;When naming things, pay attention to the following English word pairs:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;add &#x2F; remove&lt;&#x2F;li&gt;
&lt;li&gt;insert &#x2F; delete&lt;&#x2F;li&gt;
&lt;li&gt;get &#x2F; set&lt;&#x2F;li&gt;
&lt;li&gt;start &#x2F; stop&lt;&#x2F;li&gt;
&lt;li&gt;begin &#x2F; end&lt;&#x2F;li&gt;
&lt;li&gt;send &#x2F; receive&lt;&#x2F;li&gt;
&lt;li&gt;first &#x2F; last&lt;&#x2F;li&gt;
&lt;li&gt;get &#x2F; release&lt;&#x2F;li&gt;
&lt;li&gt;put &#x2F; get&lt;&#x2F;li&gt;
&lt;li&gt;up &#x2F; down&lt;&#x2F;li&gt;
&lt;li&gt;show &#x2F; hide&lt;&#x2F;li&gt;
&lt;li&gt;source &#x2F; target&lt;&#x2F;li&gt;
&lt;li&gt;open &#x2F; close&lt;&#x2F;li&gt;
&lt;li&gt;source &#x2F; destination&lt;&#x2F;li&gt;
&lt;li&gt;increment &#x2F; decrement&lt;&#x2F;li&gt;
&lt;li&gt;lock &#x2F; unlock&lt;&#x2F;li&gt;
&lt;li&gt;old &#x2F; new&lt;&#x2F;li&gt;
&lt;li&gt;next &#x2F; previous&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;loop-counters&quot;&gt;Loop Counters&lt;&#x2F;h3&gt;
&lt;p&gt;Use &lt;code&gt;i&lt;&#x2F;code&gt;, &lt;code&gt;j&lt;&#x2F;code&gt;, and &lt;code&gt;k&lt;&#x2F;code&gt; for loop counters with a narrow scope.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;variables-with-a-narrow-scope&quot;&gt;Variables with a Narrow Scope&lt;&#x2F;h3&gt;
&lt;p&gt;Abbreviations may be used for variable names with a narrow scope. However, do not overuse abbreviations to the point that readability is reduced.&lt;&#x2F;p&gt;
&lt;p&gt;Example)&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;java&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-java &quot;&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;InputStream&lt;&#x2F;span&gt;&lt;span&gt; in = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;new &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;BufferedInputStream&lt;&#x2F;span&gt;&lt;span&gt;(...);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;meaningful-names&quot;&gt;Meaningful Names&lt;&#x2F;h3&gt;
&lt;p&gt;As a general rule, use names whose meaning can be understood from the name itself.&lt;&#x2F;p&gt;
&lt;p&gt;Bad example)&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;java&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-java &quot;&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;copy&lt;&#x2F;span&gt;&lt;span&gt;(s1, s2);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Good example)&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;java&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-java &quot;&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;copy&lt;&#x2F;span&gt;&lt;span&gt;(source, destination);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;style&quot;&gt;Style&lt;&#x2F;h2&gt;
&lt;p&gt;The coding style should follow the style of the JDK source code.&lt;&#x2F;p&gt;
&lt;p&gt;It is similar to the K&amp;amp;R style for the C language, but the opening &lt;code&gt;{&lt;&#x2F;code&gt; of a class&#x2F;method definition should be written on the same line rather than on a new line.&lt;&#x2F;p&gt;
&lt;p&gt;Use &lt;a href=&quot;https:&#x2F;&#x2F;checkstyle.sourceforge.io&#x2F;&quot;&gt;Checkstyle&lt;&#x2F;a&gt; to check the style and automate the process as much as possible.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;comments&quot;&gt;Comments&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;As a general rule, write Javadoc comments for public classes and methods.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Write only necessary comments, and keep them concise.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Write comments that explain why something is done.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Write comments before writing the code.&lt;br &#x2F;&gt;
As you will find when you try it, one of the best ways to write good comments is to describe the processing concisely in comments before writing the code.&lt;br &#x2F;&gt;
If the processing consists of multiple steps, write each step as a separate line of comments before starting the implementation.&lt;br &#x2F;&gt;
This ensures that comments are written and also helps ensure that the implementation follows what was described in the comments.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Make use of &lt;code&gt;TODO&lt;&#x2F;code&gt; comments.&lt;br &#x2F;&gt;
Since IDEs such as Eclipse allow TODOs to be viewed together, use &lt;code&gt;TODO&lt;&#x2F;code&gt; comments to describe work that should be done later when something remains unfinished due to reasons such as waiting for another person&#x27;s implementation or waiting for the specification to be finalized.
&lt;em&gt;When viewing the list in Eclipse, use the &lt;code&gt;Tasks View&lt;&#x2F;code&gt;.&lt;&#x2F;em&gt;
&lt;em&gt;In addition to TODO, the following comment tags can be used as task tags.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;FIXME&lt;&#x2F;code&gt;: A fix is required.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;XXX&lt;&#x2F;code&gt;: Dangerous! It works, but it is unclear why it works.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;em&gt;There are other tags besides FIXME and XXX, but when using them in Eclipse, you need to add the comments to be used under&lt;&#x2F;em&gt;
&lt;em&gt;[Settings] &amp;gt; [Java] &amp;gt; [Compiler] &amp;gt; [Task Tags].&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;imports&quot;&gt;Imports&lt;&#x2F;h3&gt;
&lt;p&gt;As a general rule, do not use &lt;code&gt;*&lt;&#x2F;code&gt; in import statements.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;scope&quot;&gt;Scope&lt;&#x2F;h3&gt;
&lt;p&gt;Set appropriate scopes for methods and fields.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;instance-variables&quot;&gt;Instance Variables&lt;&#x2F;h3&gt;
&lt;p&gt;As a general rule, use private scope and write setters&#x2F;getters as necessary.&lt;br &#x2F;&gt;
For simple setters&#x2F;getters that only set or retrieve values, use &lt;a href=&quot;https:&#x2F;&#x2F;projectlombok.org&#x2F;&quot;&gt;Lombok&lt;&#x2F;a&gt; as appropriate to improve code readability and development efficiency.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;use-of-local-variables&quot;&gt;Use of Local Variables&lt;&#x2F;h3&gt;
&lt;p&gt;Except for entity classes, bean classes, and similar classes, avoid using instance variables as much as possible.&lt;br &#x2F;&gt;
In particular, when using a DI container such as the Spring Framework, certain classes may be instantiated as singletons by default. Therefore, using instance variables carelessly can result in a thread-unsafe implementation.&lt;br &#x2F;&gt;
As a result, a bug may not be detected during unit or integration testing and may only occur in actual production use.
In some cases, this can lead to serious problems such as the leakage of personal information, so implement such code with care.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;use-of-final&quot;&gt;Use of &lt;code&gt;final&lt;&#x2F;code&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Use &lt;code&gt;final&lt;&#x2F;code&gt; appropriately as necessary.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Classes that should not be inherited&lt;&#x2F;li&gt;
&lt;li&gt;Methods that should not be overridden&lt;&#x2F;li&gt;
&lt;li&gt;Variables whose values do not change (or should not change)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;comparison&quot;&gt;Comparison&lt;&#x2F;h3&gt;
&lt;p&gt;Use the &lt;code&gt;equals&lt;&#x2F;code&gt; method when comparing objects.
Using &lt;code&gt;==&lt;&#x2F;code&gt; is acceptable when you want to compare whether two references refer to the same instance.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;boolean-comparison&quot;&gt;Boolean Comparison&lt;&#x2F;h3&gt;
&lt;p&gt;Do not compare boolean variables in conditional expressions.&lt;&#x2F;p&gt;
&lt;p&gt;Bad example)&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;java&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-java &quot;&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(isEmpty == &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Good example)&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;java&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-java &quot;&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(isEmpty)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;loops&quot;&gt;Loops&lt;&#x2F;h3&gt;
&lt;p&gt;Use an enhanced &lt;code&gt;for&lt;&#x2F;code&gt; loop when it can be used.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;referencing-through-interfaces&quot;&gt;Referencing Through Interfaces&lt;&#x2F;h3&gt;
&lt;p&gt;As a general rule, use interfaces when declaring object references. In particular, the following coding style is sometimes seen when using the Java API, but it is not a good implementation and should be avoided.&lt;&#x2F;p&gt;
&lt;p&gt;Bad example)&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;java&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-java &quot;&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;ArrayList&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;Entry&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; list = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;new &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;ArrayList&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;Entry&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;();
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Good example)&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;java&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-java &quot;&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;List&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;Entry&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; list = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;new &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;ArrayList&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;Entry&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;();
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;numbers&quot;&gt;Numbers&lt;&#x2F;h3&gt;
&lt;p&gt;Use the &lt;code&gt;BigDecimal&lt;&#x2F;code&gt; class appropriately when necessary.&lt;br &#x2F;&gt;
Strictly speaking, arithmetic operations using primitive types or types other than &lt;code&gt;BigDecimal&lt;&#x2F;code&gt; may result in rounding errors.&lt;br &#x2F;&gt;
When exact calculations are required, such as in financial or scientific applications, &lt;code&gt;BigDecimal&lt;&#x2F;code&gt; is suitable.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;try-with-resources&quot;&gt;Try-With-Resources&lt;&#x2F;h3&gt;
&lt;p&gt;When using classes that require resource cleanup, such as streams, use try-with-resources whenever possible.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;string-concatenation&quot;&gt;String Concatenation&lt;&#x2F;h3&gt;
&lt;p&gt;When performance may be a concern with string concatenation, such as when performing string concatenation inside a loop, use &lt;code&gt;StringBuilder&lt;&#x2F;code&gt; (or &lt;code&gt;StringBuffer&lt;&#x2F;code&gt;).&lt;br &#x2F;&gt;
&lt;em&gt;Use &lt;code&gt;StringBuffer&lt;&#x2F;code&gt; when thread safety is required.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;use-of-system-out-print&quot;&gt;Use of &lt;code&gt;System.out.print&lt;&#x2F;code&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Replace it with a logging API.&lt;br &#x2F;&gt;
Except when standard output is absolutely necessary or when using it for temporary debugging purposes, do not use &lt;code&gt;System.out.print&lt;&#x2F;code&gt;, &lt;code&gt;System.err.print&lt;&#x2F;code&gt;, or related methods in production-level applications.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;It is difficult to identify where the output originated.&lt;&#x2F;li&gt;
&lt;li&gt;With a logging API, the source of the output can be identified more easily through log format configuration, and the output destination, log level, and other settings can be changed centrally.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;lambdas&quot;&gt;Lambdas&lt;&#x2F;h3&gt;
&lt;p&gt;Lambda expressions may be used wherever they are applicable.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;stream-api&quot;&gt;Stream API&lt;&#x2F;h3&gt;
&lt;p&gt;The Stream API may be used.&lt;br &#x2F;&gt;
However, because an instance is generated for each intermediate operation in the Stream API, performance may be worse than when using an enhanced &lt;code&gt;for&lt;&#x2F;code&gt; loop.&lt;br &#x2F;&gt;
When implementing performance-critical processing, it is recommended to measure the performance of each approach before deciding which implementation method to use.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;var-local-variable-type-inference&quot;&gt;&lt;code&gt;var&lt;&#x2F;code&gt; (Local-Variable Type Inference)&lt;&#x2F;h3&gt;
&lt;p&gt;As a general rule, do not use &lt;code&gt;var&lt;&#x2F;code&gt;.&lt;br &#x2F;&gt;
As can be seen from the widespread adoption of TypeScript and similar technologies, ensuring &lt;code&gt;type safety&lt;&#x2F;code&gt; is strongly emphasized in modern team development. Robustness of the code should be prioritized over the reduced effort provided by type inference.&lt;br &#x2F;&gt;
However, its use is permitted in exceptional cases where not using &lt;code&gt;var&lt;&#x2F;code&gt; would have a significantly greater disadvantage due to factors such as scope.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Enable Console Login on a KVM Guest</title>
        <published>2026-09-22T00:00:00+00:00</published>
        <updated>2026-09-22T00:00:00+00:00</updated>
        <author>
          <name>Unknown</name>
        </author>
        <link rel="alternate" href="https://mosaos.github.io/blog/kvm-console/" type="text/html"/>
        <id>https://mosaos.github.io/blog/kvm-console/</id>
        
        <content type="html">&lt;p&gt;KVM provides a feature to log in to a guest via the console. However, if the guest itself is not configured to allow console login, you will not be able to perform any operations even after connecting.&lt;&#x2F;p&gt;
&lt;p&gt;In particular, when the guest OS network settings are not yet configured, having console login available is very helpful (since you cannot connect via SSH to configure it).&lt;&#x2F;p&gt;
&lt;p&gt;Below are the steps to configure a KVM guest.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;environment&quot;&gt;Environment&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;KVM host OS : Rocky Linux 9 (upgraded from CentOS 8)&lt;&#x2F;li&gt;
&lt;li&gt;Bootloader : grub2&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The KVM environment in use is built on RHEL clone (the KVM server runs on Rocky 9 : upgraded from CentOS), and the guests also use RHEL clone.&lt;br &#x2F;&gt;
Instead of installing OS from scratch every time, a base image is created in advance. When creating a new KVM guest, this base image is cloned.&lt;&#x2F;p&gt;
&lt;p&gt;By enabling console login in the base image, all cloned guests will also support console login.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Note:&lt;&#x2F;em&gt; This procedure works with RHEL 7 and later. Earlier versions use &lt;code&gt;grub&lt;&#x2F;code&gt; instead of &lt;code&gt;grub2&lt;&#x2F;code&gt;, so the steps are different.&lt;br &#x2F;&gt;
&lt;em&gt;Note:&lt;&#x2F;em&gt; This article is based on content written and verified during the CentOS 8 era. Consequently, the output logs and version numbers (such as for the kernel and glibc) reflect that period; however, the same configuration procedures apply to RHEL 8&#x2F;9 and Rocky Linux 9.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;configuration&quot;&gt;Configuration&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;edit-etc-default-grub&quot;&gt;Edit &lt;code&gt;&#x2F;etc&#x2F;default&#x2F;grub&lt;&#x2F;code&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Modify the GRUB configuration.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vi&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;etc&#x2F;default&#x2F;grub
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Change the following line:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;GRUB_CMDLINE_LINUX&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;crashkernel=auto resume=&#x2F;dev&#x2F;mapper&#x2F;cl-swap rd.lvm.lv=cl&#x2F;root rd.lvm.lv=cl&#x2F;swap&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;to the following
(add &lt;code&gt;console=tty0 console=ttyS0,115200n8r&lt;&#x2F;code&gt; to the existing settings):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;GRUB_CMDLINE_LINUX&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;crashkernel=auto resume=&#x2F;dev&#x2F;mapper&#x2F;cl-swap rd.lvm.lv=cl&#x2F;root rd.lvm.lv=cl&#x2F;swap console=tty0 console=ttyS0,115200n8r&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After editing, regenerate the configuration:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;grub2-mkconfig -o&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;boot&#x2F;grub2&#x2F;grub.cfg
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;reboot&quot;&gt;Reboot&lt;&#x2F;h3&gt;
&lt;p&gt;Reboot after changing the GRUB settings.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;reboot
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;verification&quot;&gt;Verification&lt;&#x2F;h2&gt;
&lt;p&gt;After rebooting, verify that you can connect from the KVM host.&lt;&#x2F;p&gt;
&lt;p&gt;Check the running guests:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;virsh&lt;&#x2F;span&gt;&lt;span&gt; list&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --all
&lt;&#x2F;span&gt;&lt;span&gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Id&lt;&#x2F;span&gt;&lt;span&gt;    Name                         State
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;----------------------------------------------------
&lt;&#x2F;span&gt;&lt;span&gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;     mosaos-centos8               running
&lt;&#x2F;span&gt;&lt;span&gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;     centos8-base                 running
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Log in via the console:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;virsh&lt;&#x2F;span&gt;&lt;span&gt; console centos8-base
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Connected&lt;&#x2F;span&gt;&lt;span&gt; to domain centos8-base
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Escape&lt;&#x2F;span&gt;&lt;span&gt; character is ^]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CentOS&lt;&#x2F;span&gt;&lt;span&gt; Linux 8 (Core)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Kernel&lt;&#x2F;span&gt;&lt;span&gt; 4.18.0-193.el8.x86_64 on an x86_64
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Activate&lt;&#x2F;span&gt;&lt;span&gt; the web console with: systemctl enable&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --now&lt;&#x2F;span&gt;&lt;span&gt; cockpit.socket
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;localhost&lt;&#x2F;span&gt;&lt;span&gt; login:
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;From here, you can proceed just as you would with a local login.
If the login prompt does not appear, press the Enter key once.&lt;&#x2F;p&gt;
&lt;p&gt;To exit, use &lt;code&gt;^]&lt;&#x2F;code&gt; (&lt;code&gt;Ctrl&lt;&#x2F;code&gt; + &lt;code&gt;]&lt;&#x2F;code&gt;) as shown at the beginning.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Note:&lt;&#x2F;em&gt; Cockpit is also installed, and console login is available from Cockpit as well.
It may feel similar to logging in from the AWS console.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Changing the Disk Size of a KVM Guest</title>
        <published>2026-09-22T00:00:00+00:00</published>
        <updated>2026-09-22T00:00:00+00:00</updated>
        <author>
          <name>Unknown</name>
        </author>
        <link rel="alternate" href="https://mosaos.github.io/blog/kvm-disk-resize/" type="text/html"/>
        <id>https://mosaos.github.io/blog/kvm-disk-resize/</id>
        
        <content type="html">&lt;p&gt;Depending on the purpose of a KVM guest, the disk created initially may sometimes become insufficient in size.&lt;br &#x2F;&gt;
CPU and memory resources require a reboot, but can be changed relatively easily (subject to the resources available on the KVM host).&lt;&#x2F;p&gt;
&lt;p&gt;Disk settings can also be changed flexibly when external disks are mounted using NFS or similar methods. However, changing the disk capacity of the image itself requires some work. Since this is the kind of procedure that is easy to forget if you do not write it down somewhere, I am documenting the steps here.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;environment&quot;&gt;Environment&lt;&#x2F;h2&gt;
&lt;p&gt;The environment is as follows.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;KVM host OS: Rocky 9&lt;&#x2F;li&gt;
&lt;li&gt;KVM guest OS: Linux-based (using LVM)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The image file format I use is qcow2, so the following procedure is for qcow2.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;procedure&quot;&gt;Procedure&lt;&#x2F;h2&gt;
&lt;p&gt;* Before starting, shut down the KVM guest whose disk capacity you want to change, and back up the image if necessary.&lt;br &#x2F;&gt;
* Since a mistake when operating the commands could, in the worst case, make the system unable to boot, I recommend making a backup.&lt;&#x2F;p&gt;
&lt;p&gt;First, perform the following operations on the KVM host.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;check-the-kvm-image&quot;&gt;Check the KVM image&lt;&#x2F;h3&gt;
&lt;p&gt;Check the format and size of the KVM image.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;qemu-img&lt;&#x2F;span&gt;&lt;span&gt; info &#x2F;var&#x2F;lib&#x2F;libvirt&#x2F;images&#x2F;&amp;lt;image-file-name&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;expand-the-file-size&quot;&gt;Expand the file size&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;qemu-img&lt;&#x2F;span&gt;&lt;span&gt; resize&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -f&lt;&#x2F;span&gt;&lt;span&gt; qcow2 &amp;lt;image-file-name&amp;gt; +10G
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;* Change the &lt;code&gt;+10G&lt;&#x2F;code&gt; part as appropriate for the amount by which you want to resize the disk.&lt;&#x2F;p&gt;
&lt;p&gt;After running the command, run &lt;code&gt;qemu-img info&lt;&#x2F;code&gt; again and make sure that the size has been changed correctly.&lt;&#x2F;p&gt;
&lt;p&gt;From this point onward, the operations are performed on the KVM guest.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;using-fdisk&quot;&gt;Using fdisk&lt;&#x2F;h3&gt;
&lt;p&gt;Start the KVM guest with the image whose capacity has been increased.&lt;br &#x2F;&gt;
Run fdisk and recreate the partition.&lt;&#x2F;p&gt;
&lt;p&gt;* Change the device name as appropriate for your environment.&lt;br &#x2F;&gt;
* Although there are explanations in the middle, everything up to entering &lt;code&gt;q&lt;&#x2F;code&gt; is an operation performed with the fdisk command.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;fdisk&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;dev&#x2F;vda
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Check the current state.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Command&lt;&#x2F;span&gt;&lt;span&gt; (m for help)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; p
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;omitted&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Device&lt;&#x2F;span&gt;&lt;span&gt;     Boot    Start      End  Sectors   Size Id Type
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;&#x2F;dev&#x2F;vda1  &lt;&#x2F;span&gt;&lt;span&gt;*        2048  2099199  2097152     1G 83 Linux
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;&#x2F;dev&#x2F;vda2&lt;&#x2F;span&gt;&lt;span&gt;        2099200 41943039 39843840    19G 8e Linux LVM
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Resize the LVM on &lt;code&gt;&#x2F;dev&#x2F;vda2&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;First, delete it:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Command&lt;&#x2F;span&gt;&lt;span&gt; (m for help)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; d
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Partition&lt;&#x2F;span&gt;&lt;span&gt; number (1,2, default 2)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; 2
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then create it again.&lt;br &#x2F;&gt;
Since the basic partition 2 was deleted, recreate basic partition 2.&lt;br &#x2F;&gt;
When entering the number of sectors, the default value (just press Enter) is fine.&lt;br &#x2F;&gt;
(It will be created using all available free space.)&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Command&lt;&#x2F;span&gt;&lt;span&gt; (m for help)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; n
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Partition&lt;&#x2F;span&gt;&lt;span&gt; type
&lt;&#x2F;span&gt;&lt;span&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;p&lt;&#x2F;span&gt;&lt;span&gt;   primary (1-4)
&lt;&#x2F;span&gt;&lt;span&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;e&lt;&#x2F;span&gt;&lt;span&gt;   extended
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Select&lt;&#x2F;span&gt;&lt;span&gt; (default p)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; p
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Partition&lt;&#x2F;span&gt;&lt;span&gt; number (2-4, default 2)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; 2
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;First&lt;&#x2F;span&gt;&lt;span&gt; sector (2099200-41943039, default 2099200)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Last&lt;&#x2F;span&gt;&lt;span&gt; sector, +&#x2F;-sectors or +&#x2F;-size{K,M,G,T,P} (2099200-41943039, default 41943039)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Created&lt;&#x2F;span&gt;&lt;span&gt; a new partition  2 of type &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Linux&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39; and of size 19 GiB.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Partition &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;#2 contains a LVM2_member signature.
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Do&lt;&#x2F;span&gt;&lt;span&gt; you want to remove the signature? &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;Y&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;es&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;N&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;o: N
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;change-the-partition-type-to-linux-lvm&quot;&gt;Change the partition type to Linux LVM&lt;&#x2F;h3&gt;
&lt;p&gt;The recreated partition type is &lt;code&gt;Linux&lt;&#x2F;code&gt;, so change it to &lt;code&gt;Linux LVM&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Command&lt;&#x2F;span&gt;&lt;span&gt; (m for help)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; t
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Partition&lt;&#x2F;span&gt;&lt;span&gt; number (1,2, default 2)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; 2
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Hex&lt;&#x2F;span&gt;&lt;span&gt; code or alias (type L to list all)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; 8e
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Change&lt;&#x2F;span&gt;&lt;span&gt; type of partition &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Linux&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39; to &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Linux LVM&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Check the state after the change:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Command&lt;&#x2F;span&gt;&lt;span&gt; (m for help)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; p
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;omitted&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Device&lt;&#x2F;span&gt;&lt;span&gt;     Boot    Start      End  Sectors   Size Id Type
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;&#x2F;dev&#x2F;vda1  &lt;&#x2F;span&gt;&lt;span&gt;*        2048  2099199  2097152     1G 83 Linux
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;&#x2F;dev&#x2F;vda2&lt;&#x2F;span&gt;&lt;span&gt;        2099200 41943039 39843840    19G 8e Linux LVM
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If it has been changed to the expected state (size and partition type), write the changes and exit fdisk.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Command&lt;&#x2F;span&gt;&lt;span&gt; (m for help)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; w
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Command&lt;&#x2F;span&gt;&lt;span&gt; (m for help)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; q
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;On current operating systems (Red Hat 7 and later), &lt;code&gt;partprobe&lt;&#x2F;code&gt; should allow the changes to take effect without rebooting.&lt;br &#x2F;&gt;
* A reboot may be required depending on the OS.&lt;br &#x2F;&gt;
* &lt;code&gt;partprobe&lt;&#x2F;code&gt; itself may not even be necessary.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;partprobe
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;resize-the-physical-volume&quot;&gt;Resize the physical volume&lt;&#x2F;h3&gt;
&lt;p&gt;When using LVM, you need to resize the PV (physical volume) and LV (logical volume).&lt;&#x2F;p&gt;
&lt;p&gt;First, resize the PV (Physical Volume).&lt;&#x2F;p&gt;
&lt;p&gt;Check the current state:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;pvdisplay
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then resize it.&lt;br &#x2F;&gt;
This changes it so that all of the space corresponding to the size changed with fdisk is used.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;pvresize&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;dev&#x2F;vda2
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After resizing, run &lt;code&gt;pvdisplay&lt;&#x2F;code&gt; again to confirm the change.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;resize-the-logical-volume&quot;&gt;Resize the logical volume&lt;&#x2F;h3&gt;
&lt;p&gt;Resize the logical volume.&lt;&#x2F;p&gt;
&lt;p&gt;Check the current state:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;lvs
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;lvdisplay
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then resize it.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;lvextend -l&lt;&#x2F;span&gt;&lt;span&gt; +100%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;FREE&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;dev&#x2F;cl&#x2F;root
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Finally, expand the file system.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;xfs_growfs&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;dev&#x2F;cl&#x2F;root
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;※ On Ubuntu, you may need to use something like &lt;code&gt;resize2fs &#x2F;dev&#x2F;ubuntu-vg&#x2F;ubuntu-lv&lt;&#x2F;code&gt; instead.&lt;&#x2F;p&gt;
&lt;p&gt;Check the size.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;df
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;evtmpfs&lt;&#x2F;span&gt;&lt;span&gt;                                     912992         0     912992    0% &#x2F;dev
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;tmpfs&lt;&#x2F;span&gt;&lt;span&gt;                                        930236         0     930236    0% &#x2F;dev&#x2F;shm
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;tmpfs&lt;&#x2F;span&gt;&lt;span&gt;                                        930236      8796     921440    1% &#x2F;run
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;tmpfs&lt;&#x2F;span&gt;&lt;span&gt;                                        930236         0     930236    0% &#x2F;sys&#x2F;fs&#x2F;cgroup
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;&#x2F;dev&#x2F;mapper&#x2F;cl-root&lt;&#x2F;span&gt;&lt;span&gt;                        17811456   8021136    9790320   46% &#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;&#x2F;dev&#x2F;vda1&lt;&#x2F;span&gt;&lt;span&gt;                                    999320    262420     668088   29% &#x2F;boot
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;tmpfs&lt;&#x2F;span&gt;&lt;span&gt;                                        186044         0     186044    0% &#x2F;run&#x2F;user&#x2F;1000
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If the capacity has been expanded, the operation was successful.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Building a Docker Repository with Nexus Repository Manager</title>
        <published>2026-09-22T00:00:00+00:00</published>
        <updated>2026-09-22T00:00:00+00:00</updated>
        <author>
          <name>Unknown</name>
        </author>
        <link rel="alternate" href="https://mosaos.github.io/blog/nxrm/" type="text/html"/>
        <id>https://mosaos.github.io/blog/nxrm/</id>
        
        <content type="html">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;This article is a rewrite of an old article, so some information may be outdated. However, the NXRM built using this procedure is still running as of September 2026.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;It seems that the use of Docker has been increasing, but Docker images were not shared between developers. When using Docker, each developer had to build the images from Dockerfiles individually, which was inconvenient.&lt;&#x2F;p&gt;
&lt;p&gt;To solve this problem, I built a Docker repository. The procedure for building and using it is described below.&lt;&#x2F;p&gt;
&lt;p&gt;I used &lt;a href=&quot;https:&#x2F;&#x2F;www.sonatype.com&#x2F;nexus&#x2F;repository-oss&quot;&gt;Nexus Repository OSS&lt;&#x2F;a&gt; (&lt;code&gt;NXRM&lt;&#x2F;code&gt;) to build the repository.&lt;&#x2F;p&gt;
&lt;p&gt;NXRM is an OSS repository manager that can be used not only for Docker repositories, but also for various libraries and images such as Maven.
It can also work as a proxy for Docker Hub. In addition, by merging a private (hosted) repository with an external (cached) repository using the group repository feature, internal and external repositories can be handled transparently.&lt;&#x2F;p&gt;
&lt;p&gt;ECR (Elastic Container Registry), etc. can also be used, but NXRM may be easier to adopt for teams where it is difficult to use such services because of cost.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;In an internal LAN, it is also possible to cache Docker images and various libraries to reduce traffic.&lt;&#x2F;li&gt;
&lt;li&gt;It is also possible to build an image with GitLab CI, and then register (push) the image to NXRM. GitLab can also be self-hosted.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Using NXRM may solve repository-related problems. If you have problems like those described above, it may be worth trying.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;environment&quot;&gt;Environment&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;OS: &lt;code&gt;CentOS 8&lt;&#x2F;code&gt; (built as a KVM guest)
Currently upgraded to &lt;code&gt;Rocky 9&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;The repository directory is mounted from a directory on the host.
Since the cache repository tends to become large, I thought mounting a directory from the host would be easier to manage than managing it inside the KVM guest.&lt;&#x2F;li&gt;
&lt;li&gt;I initially tried to use 9p_virtio, but it did not work well, so I use NFS.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;help.sonatype.com&#x2F;repomanager3&#x2F;high-availability&#x2F;configuring-blob-stores&quot;&gt;Configuring Blob Stores&lt;&#x2F;a&gt; says to use NFS v4, so I use NFSv4.&lt;&#x2F;li&gt;
&lt;li&gt;Configure the NFS server on the KVM host in advance.&lt;&#x2F;li&gt;
&lt;li&gt;The directory on the host is &lt;code&gt;&#x2F;var&#x2F;opt&#x2F;nexus&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;TLS (HTTPS) is not enabled because this is operated in a closed environment with internal access only.
&lt;em&gt;There are several ways to enable TLS for NXRM. Please refer to the official documentation, etc.&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;nexus_hostname&lt;&#x2F;code&gt; is the hostname of the host where Nexus Repository Manager is installed.
If the host cannot be accessed by hostname, an IP address can also be used.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;installation-procedure-server&quot;&gt;Installation Procedure (Server)&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;dnf-update&quot;&gt;dnf update&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;dnf&lt;&#x2F;span&gt;&lt;span&gt; update
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;nfs-client-configuration&quot;&gt;NFS Client Configuration&lt;&#x2F;h3&gt;
&lt;p&gt;Mount the directory on the KVM host using NFS.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;install-the-package&quot;&gt;Install the package&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;dnf -y&lt;&#x2F;span&gt;&lt;span&gt; install nfs-utils
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h4 id=&quot;edit-the-configuration-file&quot;&gt;Edit the configuration file&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vi&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;etc&#x2F;idmapd.conf
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Edit the following part:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;Domain = mosaos.local
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h4 id=&quot;mount&quot;&gt;Mount&lt;&#x2F;h4&gt;
&lt;p&gt;First, check whether it can be mounted.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;mount -t&lt;&#x2F;span&gt;&lt;span&gt; nfs kvmhost:&#x2F;var&#x2F;opt&#x2F;nexus &#x2F;mnt
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If it works, unmount it.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;umount&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;mnt
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Add the configuration to &lt;code&gt;&#x2F;etc&#x2F;fstab&lt;&#x2F;code&gt; so that it is automatically mounted.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vi&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;etc&#x2F;fstab
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Add the following:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;kvmhost:&#x2F;var&#x2F;opt&#x2F;nexus &#x2F;opt&#x2F;sonatype-work nfs4 rw,sync,tcp,hard,intr,rsize=32768,wsize=32768 0 0
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Mount it.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;mount -a
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;install-nxrm&quot;&gt;Install NXRM&lt;&#x2F;h3&gt;
&lt;p&gt;Install it using &lt;code&gt;ansible-playbook&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mosaos&#x2F;sonatype-nexus3-ansible&quot;&gt;mosaos&#x2F;sonatype-nexus3-ansible&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Clone the project:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; clone https:&#x2F;&#x2F;github.com&#x2F;mosaos&#x2F;sonatype-nexus3-ansible
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Run ansible-playbook:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;cd&lt;&#x2F;span&gt;&lt;span&gt; sonatype_nexus3_ansible
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ansible-playbook -i&lt;&#x2F;span&gt;&lt;span&gt; hosts site.yml
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;nxrm-configuration&quot;&gt;NXRM Configuration&lt;&#x2F;h3&gt;
&lt;p&gt;The configuration is mostly based on the following article:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.sonatype.com&#x2F;using-nexus-3-as-your-repository-part-3-docker-images&quot;&gt;Using Nexus 3 as Your Repository - Part 3: Docker Images&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Create the following repositories:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Name&lt;&#x2F;th&gt;&lt;th&gt;Type&lt;&#x2F;th&gt;&lt;th&gt;Port (HTTP)&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;docker-private&lt;&#x2F;td&gt;&lt;td&gt;docker (hosted)&lt;&#x2F;td&gt;&lt;td&gt;5001&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;docker-hub&lt;&#x2F;td&gt;&lt;td&gt;docker (proxy)&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;docker-group&lt;&#x2F;td&gt;&lt;td&gt;docker (group)&lt;&#x2F;td&gt;&lt;td&gt;5000&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;The settings when creating each repository are as follows.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;docker-private&quot;&gt;docker-private&lt;&#x2F;h4&gt;
&lt;ul&gt;
&lt;li&gt;Create it as &lt;code&gt;docker (hosted)&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Check HTTP and specify the port number (&lt;code&gt;5001&lt;&#x2F;code&gt;).&lt;&#x2F;li&gt;
&lt;li&gt;Check &lt;code&gt;Enable Docker V1 API:&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;docker-hub&quot;&gt;docker-hub&lt;&#x2F;h4&gt;
&lt;ul&gt;
&lt;li&gt;Create it as &lt;code&gt;docker (proxy)&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Specify &lt;code&gt;https:&#x2F;&#x2F;registry-1.docker.io&lt;&#x2F;code&gt; for &lt;code&gt;Remote storage:&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Select &lt;code&gt;User Docker Hub&lt;&#x2F;code&gt; for &lt;code&gt;Docker Index:&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Check &lt;code&gt;Enable Docker V1 API:&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;docker-group&quot;&gt;docker-group&lt;&#x2F;h4&gt;
&lt;ul&gt;
&lt;li&gt;Create it as &lt;code&gt;docker (group)&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Check HTTP and specify the port number (&lt;code&gt;5000&lt;&#x2F;code&gt;).&lt;&#x2F;li&gt;
&lt;li&gt;Add the two repositories created above to &lt;code&gt;Member repositories:&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Check &lt;code&gt;Enable Docker V1 API:&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;blockquote&gt;
&lt;p&gt;In my environment, I could not push unless &lt;code&gt;Enable Docker V1 API:&lt;&#x2F;code&gt; was checked.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;additional-firewall-configuration&quot;&gt;Additional Firewall Configuration&lt;&#x2F;h3&gt;
&lt;p&gt;After creating the repositories, allow &lt;code&gt;5000&#x2F;tcp&lt;&#x2F;code&gt; and &lt;code&gt;5001&#x2F;tcp&lt;&#x2F;code&gt; on the host where NXRM is installed.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;firewall-cmd --add-port&lt;&#x2F;span&gt;&lt;span&gt;=5000&#x2F;tcp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --permanent --zone&lt;&#x2F;span&gt;&lt;span&gt;=public
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;firewall-cmd --add-port&lt;&#x2F;span&gt;&lt;span&gt;=5001&#x2F;tcp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --permanent --zone&lt;&#x2F;span&gt;&lt;span&gt;=public
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;firewall-cmd --reload
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;installation-procedure-client&quot;&gt;Installation Procedure (Client)&lt;&#x2F;h2&gt;
&lt;p&gt;Set up the Docker environment.&lt;&#x2F;p&gt;
&lt;p&gt;A configuration is required to connect to a repository that does not use TLS.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;environment-1&quot;&gt;Environment&lt;&#x2F;h3&gt;
&lt;p&gt;I confirmed this procedure with the following environment.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;OS: CentOS 8&lt;&#x2F;li&gt;
&lt;li&gt;Docker: 19.03.8&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;connectivity-check&quot;&gt;Connectivity Check&lt;&#x2F;h3&gt;
&lt;p&gt;When sending a request to NXRM with curl, if it returns a response saying that it is not a Docker request, it is OK.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;curl&lt;&#x2F;span&gt;&lt;span&gt; http:&#x2F;&#x2F;nexus_hostname:5000&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;html&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;head&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;meta &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;http-equiv&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Content-Type&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;content&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;text&#x2F;html;charset=utf-8&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;title&amp;gt;Error &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;400&lt;&#x2F;span&gt;&lt;span&gt; Not a Docker request&amp;lt;&#x2F;title&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&#x2F;head&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;body&amp;gt;&amp;lt;h2&amp;gt;HTTP &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ERROR&lt;&#x2F;span&gt;&lt;span&gt; 400 Not a Docker request&amp;lt;&#x2F;h2&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;table&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;URI:&amp;lt;&#x2F;th&amp;gt;&amp;lt;td&amp;gt;&#x2F;&amp;lt;&#x2F;td&amp;gt;&amp;lt;&#x2F;tr&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;STATUS:&amp;lt;&#x2F;th&amp;gt;&amp;lt;td&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;400&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&#x2F;td&amp;gt;&amp;lt;&#x2F;tr&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;MESSAGE:&amp;lt;&#x2F;th&amp;gt;&amp;lt;td&amp;gt;Not &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt; Docker request&amp;lt;&#x2F;td&amp;gt;&amp;lt;&#x2F;tr&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;SERVLET:&amp;lt;&#x2F;th&amp;gt;&amp;lt;td&amp;gt;-&amp;lt;&#x2F;td&amp;gt;&amp;lt;&#x2F;tr&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&#x2F;table&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;hr&amp;gt;&amp;lt;a &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;href&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;http:&#x2F;&#x2F;eclipse.org&#x2F;jetty&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&amp;gt;Powered &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;by&lt;&#x2F;span&gt;&lt;span&gt; Jetty:&#x2F;&#x2F; 9.4.30.v&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;20200611&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&#x2F;a&amp;gt;&amp;lt;                                                                                                                                         hr&#x2F;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&#x2F;body&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&#x2F;html&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;configure-daemon-json&quot;&gt;Configure daemon.json&lt;&#x2F;h3&gt;
&lt;p&gt;Create &lt;code&gt;daemon.json&lt;&#x2F;code&gt; and configure Docker.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vi&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;etc&#x2F;docker&#x2F;daemon.json
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;When using a repository that does not use TLS, it must be specified in &lt;code&gt;insecure-registries&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;It is also possible to specify this every time on the command line, but it is troublesome, so I recommend configuring the Docker daemon.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Add the registries created in NXRM to &lt;code&gt;insecure-registries&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;json&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-json &quot;&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;debug&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;insecure-registries&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;: [&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;nexus_hostname:5000&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;nexus_hostname:5001&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;The configuration when also using the mirror setting is described below.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;After creating &lt;code&gt;daemon.json&lt;&#x2F;code&gt;, restart the Docker daemon.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;systemctl&lt;&#x2F;span&gt;&lt;span&gt; restart docker
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;registering-pushing-docker-images&quot;&gt;Registering (Pushing) Docker Images&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;log-in-to-nxrm&quot;&gt;Log in to NXRM&lt;&#x2F;h3&gt;
&lt;p&gt;Specify an NXRM user for the username and password.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;docker&lt;&#x2F;span&gt;&lt;span&gt; login nexus_hostname:5000
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;docker&lt;&#x2F;span&gt;&lt;span&gt; login nexus_hostname:5001
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You will be asked to enter a username and password. Log in with your own account.&lt;&#x2F;p&gt;
&lt;p&gt;A WARNING will be displayed when running the command, but if &lt;code&gt;Login Succeeded&lt;&#x2F;code&gt; is displayed, the login was successful.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The authentication information is recorded in &lt;code&gt;~&#x2F;.docker&#x2F;config.json&lt;&#x2F;code&gt; after running the command.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;push&quot;&gt;Push&lt;&#x2F;h3&gt;
&lt;p&gt;Push the image to the hosted repository.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;docker&lt;&#x2F;span&gt;&lt;span&gt; tag image_name:version nexus_hostname:5001&#x2F;image_name:version
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;docker&lt;&#x2F;span&gt;&lt;span&gt; push nexus_hostname:5001&#x2F;library&#x2F;image_name:version
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For some reason, if I did not add &lt;code&gt;library&lt;&#x2F;code&gt;, I got a 404 (NOT FOUND) when pulling.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;I think it may be necessary to use a tag such as &lt;code&gt;accountname&#x2F;imagename:version&lt;&#x2F;code&gt;, in the same way as Docker Hub.
Official images do not have the account name part, but in this kind of tagging, they seem to be under &lt;code&gt;library&lt;&#x2F;code&gt;. In fact, when I downloaded the official MariaDB image and checked it in the proxy repository, its name was &lt;code&gt;library&#x2F;mariadb&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;pull&quot;&gt;Pull&lt;&#x2F;h3&gt;
&lt;p&gt;Check whether the pushed image can be retrieved.&lt;&#x2F;p&gt;
&lt;p&gt;The destination is not the hosted repository that was registered above, but the group repository that combines the hosted and proxy repositories.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;docker&lt;&#x2F;span&gt;&lt;span&gt; pull nexus_hostname:5000&#x2F;image_name:version
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;mirror-configuration&quot;&gt;Mirror Configuration&lt;&#x2F;h2&gt;
&lt;p&gt;With the configuration so far, it is possible to register (push) and retrieve (pull) Docker images that were created by ourselves from the repository server.&lt;&#x2F;p&gt;
&lt;p&gt;However, with this configuration, our own images and external images (hosted on Docker Hub) cannot be handled transparently.&lt;&#x2F;p&gt;
&lt;p&gt;Change the configuration so that they can be handled transparently.&lt;&#x2F;p&gt;
&lt;p&gt;Specifically, even when retrieving an image hosted by ourselves, it should be possible to retrieve it without specifying &lt;code&gt;repository-server:port&lt;&#x2F;code&gt;, as follows.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;When pushing, &lt;code&gt;repository-server:port&lt;&#x2F;code&gt; must be specified.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;docker&lt;&#x2F;span&gt;&lt;span&gt; pull image_name:version
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Docker can be configured to use &lt;code&gt;registry-mirrors&lt;&#x2F;code&gt; as a Docker Hub mirror, so it should be possible to solve this by configuring the group repository we created as the mirror.&lt;&#x2F;p&gt;
&lt;p&gt;However, there is a problem where authentication information is not correctly passed to the mirror site, so some additional configuration is necessary.&lt;&#x2F;p&gt;
&lt;p&gt;Reference: &lt;a href=&quot;https:&#x2F;&#x2F;qiita.com&#x2F;fukasawah&#x2F;items&#x2F;48330564736d3368b632#registry-mirrors%E3%81%8C%E6%A9%9F%E8%83%BD%E3%81%97%E3%81%AA%E3%81%84&quot;&gt;registry-mirrorsが機能しない&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;As a solution, I use the method described in &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;moby&#x2F;moby&#x2F;issues&#x2F;30880&quot;&gt;Docker is not passing auth informations when pulling from a mirror registry #30880&lt;&#x2F;a&gt;, where the authentication information is overwritten on the Nginx (proxy) side and the request is sent to Nexus.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;edit-the-nginx-configuration&quot;&gt;Edit the nginx Configuration&lt;&#x2F;h3&gt;
&lt;p&gt;I finally used the following configuration.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;events &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    worker_connections  1024;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;http &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  proxy_send_timeout 120;
&lt;&#x2F;span&gt;&lt;span&gt;  proxy_read_timeout 300;
&lt;&#x2F;span&gt;&lt;span&gt;  proxy_buffering    off;
&lt;&#x2F;span&gt;&lt;span&gt;  keepalive_timeout  5 5;
&lt;&#x2F;span&gt;&lt;span&gt;  tcp_nodelay        on;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  log_format upstreamlog &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;time_local&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;] &lt;&#x2F;span&gt;&lt;span&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;remote_addr&lt;&#x2F;span&gt;&lt;span&gt; -  $&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;host&lt;&#x2F;span&gt;&lt;span&gt; - $&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;upstream_addr&lt;&#x2F;span&gt;&lt;span&gt; - $&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;request&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  access_log &#x2F;var&#x2F;log&#x2F;nginx&#x2F;upstream.log upstreamlog;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  server {
&lt;&#x2F;span&gt;&lt;span&gt;    listen   *:80;
&lt;&#x2F;span&gt;&lt;span&gt;    server_name  www.example.com;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# allow large uploads of files
&lt;&#x2F;span&gt;&lt;span&gt;    client_max_body_size 1G;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# optimize downloading files larger than 1G
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;#proxy_max_temp_file_size 2G;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    location &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt; ^&#x2F;(v1|v2)&#x2F; {
&lt;&#x2F;span&gt;&lt;span&gt;      if ($&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;authorization&lt;&#x2F;span&gt;&lt;span&gt; = &amp;#39;&amp;#39;) {
&lt;&#x2F;span&gt;&lt;span&gt;        set $&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;authorization &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Basic XyzAbCdefg1234567890Mzk2Zi00NWYxLWJiNjYtN2ExOWRkM2EyOTVk&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;;
&lt;&#x2F;span&gt;&lt;span&gt;      }
&lt;&#x2F;span&gt;&lt;span&gt;      proxy_pass http:&#x2F;&#x2F;127.0.0.1:5000;
&lt;&#x2F;span&gt;&lt;span&gt;      proxy_set_header   Authorization $&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;authorization&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      proxy_set_header   Host $&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;host&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      proxy_set_header   X-Real-IP $&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;remote_addr&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      proxy_set_header   X-Forwarded-For $&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;proxy_add_x_forwarded_for&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      proxy_set_header   X-Forwarded-Proto $&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;scheme&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      proxy_set_header   X-Forwarded-Port $&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;server_port&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    location &#x2F; {
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# Use IPv4 upstream address instead of DNS name to avoid attempts by nginx to use IPv6 DNS lookup
&lt;&#x2F;span&gt;&lt;span&gt;      proxy_pass http:&#x2F;&#x2F;127.0.0.1:8081&#x2F;;
&lt;&#x2F;span&gt;&lt;span&gt;      proxy_set_header Host $&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;host&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      proxy_set_header X-Real-IP $&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;remote_addr&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      proxy_set_header X-Forwarded-For $&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;proxy_add_x_forwarded_for&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;When accessing a repository, the URL starts with &lt;code&gt;&#x2F;v1&lt;&#x2F;code&gt; or &lt;code&gt;&#x2F;v2&lt;&#x2F;code&gt;, so in this case the request is forwarded to the group repository.
At this time, authentication information is set using &lt;code&gt;proxy_set_header Authorization ...&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The Basic Authentication value to set in &lt;code&gt;$authorization&lt;&#x2F;code&gt; can be generated as follows.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;echo &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;-n &lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;username:password&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39; | &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;base64
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The above configuration also outputs &lt;code&gt;upstreamlog&lt;&#x2F;code&gt; so that the actual forwarding destination can be checked.&lt;&#x2F;p&gt;
&lt;p&gt;I noticed the problem where pulling did not work unless I added &lt;code&gt;library&lt;&#x2F;code&gt; when pushing by checking this log.
If an image can be pushed but cannot be pulled and a 404 occurs, the URL that the Docker client uses to retrieve the manifests may be different from the location where the image was pushed.
In this case, checking &lt;code&gt;upstreamlog&lt;&#x2F;code&gt; may help solve the problem.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;restart-nginx&quot;&gt;Restart nginx&lt;&#x2F;h3&gt;
&lt;p&gt;Check that there are no problems with the configuration:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;nginx -t
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If there are no problems, restart it.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;systemctl&lt;&#x2F;span&gt;&lt;span&gt; restart nginx
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;client-side-configuration&quot;&gt;Client-side Configuration&lt;&#x2F;h3&gt;
&lt;p&gt;Change &lt;code&gt;&#x2F;etc&#x2F;docker&#x2F;daemon.json&lt;&#x2F;code&gt; as follows.
Specify the Nexus host in &lt;code&gt;registry-mirrors&lt;&#x2F;code&gt; and &lt;code&gt;insecure-registries&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;quot;debug&amp;quot;: true,
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;quot;insecure-registries&amp;quot;: [
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;quot;nexus_hostname&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;quot;nexus_hostname:5000&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;quot;nexus_hostname:5001&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  ],
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;quot;registry-mirrors&amp;quot;: [
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;quot;http:&#x2F;&#x2F;nexus_hostname&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  ]
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;troubleshooting&quot;&gt;Troubleshooting&lt;&#x2F;h2&gt;
&lt;p&gt;The mirror configuration was the most difficult part for me.&lt;&#x2F;p&gt;
&lt;p&gt;When a problem occurs, I recommend checking the following.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Docker (client-side) logs
In my environment, they were output to syslog (&lt;code&gt;&#x2F;var&#x2F;log&#x2F;messages&#x2F;&lt;&#x2F;code&gt;).&lt;&#x2F;li&gt;
&lt;li&gt;Nexus Repository Manager logs
The output directory is &lt;code&gt;&#x2F;opt&#x2F;sonatype-work&#x2F;nexus3&#x2F;log&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;nginx logs
If you are using a proxy, also use the &lt;code&gt;upstreamlog&lt;&#x2F;code&gt; described above.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;incorrect-request-destination&quot;&gt;Incorrect Request Destination&lt;&#x2F;h3&gt;
&lt;p&gt;When I pushed an image without adding &lt;code&gt;library&lt;&#x2F;code&gt;, it was pushed to the hosted repository with the following structure:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;&#x2F;v2
&lt;&#x2F;span&gt;&lt;span&gt;  |- blobs
&lt;&#x2F;span&gt;&lt;span&gt;  |  |- sha256:.....
&lt;&#x2F;span&gt;&lt;span&gt;  |  |- sha256:.....
&lt;&#x2F;span&gt;&lt;span&gt;  |  |- sha256:.....
&lt;&#x2F;span&gt;&lt;span&gt;  |  |- sha256:.....
&lt;&#x2F;span&gt;&lt;span&gt;  |- image_name
&lt;&#x2F;span&gt;&lt;span&gt;    |- manifests
&lt;&#x2F;span&gt;&lt;span&gt;    |  |- sha256:...
&lt;&#x2F;span&gt;&lt;span&gt;    |- tags
&lt;&#x2F;span&gt;&lt;span&gt;       |- latest
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After configuring the mirror, when I ran &lt;code&gt;docker pull image_name&lt;&#x2F;code&gt;, the following error was output in the Docker log:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;Oct 13 02:36:40 localhost dockerd[17647]: time=&amp;quot;2020-10-13T02:36:40.054981034-04:00&amp;quot; level=info msg=&amp;quot;Attempting next endpoint for pull after error: Get https:&#x2F;&#x2F;nexus_hostname:5000&#x2F;v2&#x2F;library&#x2F;image_name&#x2F;manifests&#x2F;latest: unauthorized: access to the requested resource is not authorized&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I found that it was accessing &lt;code&gt;&#x2F;v2&#x2F;library&#x2F;image_name&#x2F;...&lt;&#x2F;code&gt;.
(In fact, I noticed this from &lt;code&gt;upstreamlog&lt;&#x2F;code&gt; before checking the Docker log.)&lt;&#x2F;p&gt;
&lt;p&gt;After pushing the image again as follows, I confirmed that it could be pulled.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;docker&lt;&#x2F;span&gt;&lt;span&gt; push nexus_hostname:5001&#x2F;library&#x2F;image_name:latest
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;docker&lt;&#x2F;span&gt;&lt;span&gt; pull image_name
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;references&quot;&gt;References&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.sonatype.com&#x2F;using-nexus-3-as-your-repository-part-3-docker-images&quot;&gt;Using Nexus 3 as Your Repository - Part 3: Docker Images&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;help.sonatype.com&#x2F;repomanager3&#x2F;installation&quot;&gt;Installation&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;help.sonatype.com&#x2F;repomanager3&#x2F;high-availability&#x2F;configuring-blob-stores&quot;&gt;Configuring Blob Stores&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;koudaiii&#x2F;e0e75072cc54e87e06a1&quot;&gt;NFS v4の設定内容まとめ&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;qiita.com&#x2F;fukasawah&#x2F;items&#x2F;48330564736d3368b632#registry-mirrors%E3%81%8C%E6%A9%9F%E8%83%BD%E3%81%97%E3%81%AA%E3%81%84&quot;&gt;registry-mirrorsが機能しない&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;moby&#x2F;moby&#x2F;issues&#x2F;30880&quot;&gt;Docker is not passing auth informations when pulling from a mirror registry #30880&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Wedding Dress</title>
        <published>2026-09-22T00:00:00+00:00</published>
        <updated>2026-09-22T00:00:00+00:00</updated>
        <author>
          <name>Unknown</name>
        </author>
        <link rel="alternate" href="https://mosaos.github.io/works/wedding-dress/" type="text/html"/>
        <id>https://mosaos.github.io/works/wedding-dress/</id>
        
        <content type="html">&lt;h2 id=&quot;why-did-i-make-it&quot;&gt;Why did I make it?&lt;&#x2F;h2&gt;
&lt;p&gt;My late wife (a graduate of SVA in NYC who passed away young from lung adenocarcinoma) apparently wanted to wear a dress she had imagined for our wedding, so I made one that was as close to her vision as possible. :D&lt;&#x2F;p&gt;
&lt;p&gt;Her image was that of a fairy. It was quite different from an ordinary wedding dress, with a single piece of fabric softly spreading out from the chest. In the front, the fabric curled inward just above the knees, while in the back, the drape flowed naturally like a conventional wedding dress.&lt;&#x2F;p&gt;
&lt;p&gt;We looked at quite a few dresses while shopping for one, but there was nothing that matched her vision. So I decided to make one myself...&lt;&#x2F;p&gt;
&lt;h2 id=&quot;material-procurement&quot;&gt;Material Procurement&lt;&#x2F;h2&gt;
&lt;p&gt;I went looking for fabric in Nippori Textile Town and eventually found what I needed at Tomato, a fabric store there.&lt;&#x2F;p&gt;
&lt;p&gt;The dress wouldn&#x27;t have the right shape without a petticoat, so I made that too. (I remember the petticoat actually took longer to make.)&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;mosaos.github.io&#x2F;works&#x2F;wedding-dress&#x2F;wedding-dress-01.webp&quot; alt=&quot;Dress&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;mosaos.github.io&#x2F;works&#x2F;wedding-dress&#x2F;wedding-dress-02.webp&quot; alt=&quot;Dress&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Later, one of my wife&#x27;s friends said, &amp;quot;I&#x27;d love to wear it!&amp;quot; and my wife generously gave the dress to her.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Leather Body Bag</title>
        <published>2026-09-21T00:00:00+00:00</published>
        <updated>2026-09-21T00:00:00+00:00</updated>
        <author>
          <name>Unknown</name>
        </author>
        <link rel="alternate" href="https://mosaos.github.io/works/leather-bodybag/" type="text/html"/>
        <id>https://mosaos.github.io/works/leather-bodybag/</id>
        
        <content type="html">&lt;p&gt;I made this body bag after the body bag I received from my late wife became worn out.&lt;br &#x2F;&gt;
The main part of the original bag had become badly worn, but the belt was still in good condition, so I reused the belt.&lt;br &#x2F;&gt;
I happened to find some nice Japanese leather at Hands Shinjuku during a leather fair featuring leather from Japanese tanneries, so I used it for this bag.&lt;&#x2F;p&gt;
&lt;p&gt;I used black leather for the bottom part, with a separate piece for the transition.&lt;br &#x2F;&gt;
The leather parts were hand-stitched.&lt;br &#x2F;&gt;
The inner bag was sewn with a sewing machine.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;mosaos.github.io&#x2F;works&#x2F;leather-bodybag&#x2F;.&#x2F;leather-bodybag-06.jpg&quot; alt=&quot;bag&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Nudibranch Pottery</title>
        <published>2026-09-20T00:00:00+00:00</published>
        <updated>2026-09-20T00:00:00+00:00</updated>
        <author>
          <name>Unknown</name>
        </author>
        <link rel="alternate" href="https://mosaos.github.io/works/nudibranch-pottery/" type="text/html"/>
        <id>https://mosaos.github.io/works/nudibranch-pottery/</id>
        
        <content type="html">&lt;h2 id=&quot;inspiration&quot;&gt;Inspiration&lt;&#x2F;h2&gt;
&lt;p&gt;My late wife (a graduate of SVA in NYC, who passed away at a young age from lung adenocarcinoma) practiced pottery painting. I also once made several ceramic figures by shaping pottery clay.&lt;&#x2F;p&gt;
&lt;p&gt;Nudibranchs.&lt;&#x2F;p&gt;
&lt;p&gt;I made these around the time I came across a book of nudibranch photographs and was fascinated by their beauty.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;mosaos.github.io&#x2F;works&#x2F;nudibranch-pottery&#x2F;nudibranch-01.jpg&quot; alt=&quot;Sea Slug 01&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;mosaos.github.io&#x2F;works&#x2F;nudibranch-pottery&#x2F;nudibranch-02.jpg&quot; alt=&quot;Sea Slug 02&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-happened-afterwards&quot;&gt;What Happened Afterwards&lt;&#x2F;h2&gt;
&lt;p&gt;They were displayed at my wife&#x27;s pottery exhibitions and other shows, but before I knew it, they had all disappeared.&lt;&#x2F;p&gt;
&lt;p&gt;Maybe they&#x27;re still with the people who bought them.&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
